35

If you open a file that you don't have permission to write to in vim, then decide you need to change it, you can write your changes without exiting vim by doing :w !sudo tee %
I don't understand how this can work. Can you please dissect this?
I understand the :w part, it writes the current buffer to disk, assuming there already is a file name associated with it, right?
I also understand the ! which executes the sudo tee command and % represents the current buffer content right?
But still don't understand how this works.

3 Answers 3

44

The structure :w !cmd means "write the current buffer piped through command". So you can do, for example :w !cat and it will pipe the buffer through cat.

Now % is the filename associated with the buffer

So :w !sudo tee % will pipe the contents of the buffer through sudo tee FILENAME. This effectively writes the contents of the buffer out to the file.

2
  • And what is tee? Commented Dec 5, 2019 at 18:07
  • tee is a Linux command used to split streams, like a "T-splitter" in plumbing. More info at Wikipedia: en.wikipedia.org/wiki/Tee_(command) Commented May 27, 2021 at 13:50
11

% represents the current buffer's filename, not its contents.

so :w !sudo tee % means pipe the current buffer to sudo tee [currentfilename].

tee is being run as root, so has write access to save its stdin to the file.

See also https://stackoverflow.com/questions/2600783/how-does-the-vim-write-with-sudo-trick-work

4

Not quite right!

!command runs command as a filter command, which get text from stdin, do something and output to stdout.

By using w, you pushed file content to stdin of sudo tee %. % is special register in vim, which holds the name of current file.

So you got sudo tee FILENAME, which will push tee stdin - file content - to current file.

1
  • 2
    :!command is a filter (cf. :h !), while :w !command is not, it just executes command with the current file as stdin (cf. :h :w_c). To wit: :w !sed /./d doesn't change the content of the current buffer. But the recipe is indeed not quite right for another reason, % needs to be escaped: :exec 'w !sudo tee ' . shellescape(expand('%', 1)). The original command doesn't work with, say, filenames with spaces. Commented Aug 4, 2016 at 12:11

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.