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编写”技巧如何工作?