How does the vim "write with sudo" trick work?
Many of you have probably seen the command that allows you to write on a file that needs root permission, even when you forgot to open vim with sudo:
:w !sudo tee %
The thing is that I don't get what is exactly happening here.
I have already figured this: w
is for this
*:w_c* *:write_c*
:[range]w[rite] [++opt] !{cmd}
Execute {cmd} with [range] lines as standard input
(note the space in front of the '!'). {cmd} is
executed like with ":!{cmd}", any '!' is replaced with
the previous command |:!|.
so it passes all the lines as standard input.
The !sudo tee
part calls tee
with administrator privileges.
For all to make sense, the %
should output the filename (as a parameter for tee
), but I can't find references on the help for this behavior.
tl;dr Could someone help me dissect this command?
%
means "the current file"
As eugene y pointed out, %
does indeed mean "the current file name". Another use for this in Vim is in substitution commands. For example, :%s/foo/bar
means " in the current file , replace occurrences of foo
with bar
." If you highlight some text before typing :s
, you'll see that the highlighted lines take the place of %
as your substitution range.
:w
isn't updating your file
One confusing part of this trick is that you might think :w
is modifying your file, but it isn't. If you opened and modified file1.txt
, then ran :w file2.txt
, it would be a "save as"; file1.txt
wouldn't be modified, but the current buffer contents would be sent to file2.txt
.
Instead of file2.txt
, you can substitute a shell command to receive the buffer contents . For instance, :w !cat
will just display the contents.
If Vim wasn't run with sudo access, its :w
can't modify a protected file, but if it passes the buffer contents to the shell, a command in the shell can be run with sudo . In this case, we use tee
.
Understanding tee
As for tee
, picture the tee
command as a T-shaped pipe in a normal bash piping situation: it directs output to specified file(s) and also sends it to standard output , which can be captured by the next piped command.
For example, in ps -ax | tee processes.txt | grep 'foo'
ps -ax | tee processes.txt | grep 'foo'
ps -ax | tee processes.txt | grep 'foo'
, the list of processes will be written to a text file and passed along to grep
.
+-----------+ tee +------------+
| | -------- | |
| ps -ax | -------- | grep 'foo' |
| | || | |
+-----------+ || +------------+
||
+---------------+
| |
| processes.txt |
| |
+---------------+
(Diagram created with Asciiflow.)
See the tee
man page for more info.
Tee as a hack
In the situation your question describes, using tee
is a hack because we're ignoring half of what it does . sudo tee
writes to our file and also sends the buffer contents to standard output, but we ignore standard output . We don't need to pass anything to another piped command in this case; we're just using tee
as an alternate way of writing a file and so that we can call it with sudo
.
Making this trick easy
You can add this to your .vimrc
to make this trick easy-to-use: just type :w!!
.
" Allow saving of files as sudo when I forgot to start vim using sudo.
cmap w!! w !sudo tee > /dev/null %
The > /dev/null
part explicitly throws away the standard output, since, as I said, we don't need to pass anything to another piped command.
In the executed command line, %
stands for the current file name . This is documented in :help cmdline-special
:
In Ex commands, at places where a file name can be used, the following
characters have a special meaning.
% Is replaced with the current file name.
As you've already found out, :w !cmd
pipes the contents of the current buffer to another command. What tee
does is copy standard input to one or more files, and also to standard output. Therefore, :w !sudo tee % > /dev/null
effectively writes the contents of the current buffer to the current file while being root . Another command that can be used for this is dd
:
:w !sudo dd of=% > /dev/null
As a shortcut, you can add this mapping to your .vimrc
:
" Force saving files that require root permission
cnoremap w!! w !sudo tee > /dev/null %
With the above you can type :w!!<Enter>
to save the file as root.
:w
- Write a file.
!sudo
- Call shell sudo command.
tee
- The output of write (vim :w) command redirected using tee. The % is nothing but current file name ie /etc/apache2/conf.d/mediawiki.conf. In other words tee command is run as root and it takes standard input and write it to a file represented by %. However, this will prompt to reload file again (hit L to load changes in vim itself):
tutorial link
链接地址: http://www.djcxy.com/p/28612.html上一篇: 如何在vim中缩进特定的代码块?
下一篇: vim“用sudo编写”技巧如何工作?