Comments on Vim Sudo Write Trick
CRMD said:
20+ years of using Unix and vi, and still learning tricks. Love it!
LP said:
The quotes around the percent sign are unnecessary. The
command :w !sudo tee %
works just fine. I use it
everytime!
Susam Pal said:
LP,
Like I explained in my blog post, the quotes around the percent sign are necessary to keep the filename as a single argument when the filename contains whitespace. If there is no whitespace in the filename, then the quotes are not necessary.
Here is an experiment that demonstrates the purpose of quotes:
-
Enter the following command to create a filename with a space in it and then open it with Vim:
sudo touch "foo bar.txt" vim "foo bar.txt"
-
In Vim, insert some text with the following key sequence: i hello <esc>.
-
Now enter the following command in Vim to save the file:
:w !sudo tee %
-
In another instance of the terminal, enter the following command to check the content of the file:
cat "foo bar.txt"
The file still appears empty. Nothing was saved to this file.
-
Now enter the following commands:
cat foo cat bar.txt
Both files contain the text
hello
in them.
This experiment shows that due to the lack of quotes
around %
, the command tee %
expands
to tee foo bar.txt
which ends up writing the content of
the buffer to both files foo
and bar.txt
but not to "foo bar.txt"
as we desire.
This is why we need to write tee "%"
so that it expands
to tee "foo bar.txt"
and the content of the buffer is
written to the file named "foo bar.txt"
.
Oars said:
Very useful, thanks for sharing.
RGovostes said:
I have often wished there were something equivalent for nano. Of
course you can just save to another file and sudo mv
it
into place.
In the spirit of this trick, you could set the SPELL
environment variable to a script that does
#!/bin/sh
read -p "Path: " FILENAME
cat "$1" | sudo tee "$FILENAME"
and then invoke it with ^T
from nano. Bonus points:
Extract the destination filename automatically from ps -p
$PPID -o command=
(somewhat portable) or
from /proc
(Linux).
Susam Pal said:
RGovostes, Thanks for the interesting idea to make this trick work
with nano. Based on your comment, I wrote this script to
automatically detect the destination filename when invoked
with ^T
from nano.
#!/bin/sh
set -e
COMMAND=$(ps -p $PPID -o args=)
FILENAME=${COMMAND#*nano }
printf "Write to $FILENAME? (y/n) "
read ANSWER
[ "$ANSWER" = y ] && sudo tee "$FILENAME" < "$1" > /dev/null
After saving this file to, say,
/usr/local/bin/sudowrite
, it can be set up for usage
like this:
sudo chmod u+x /usr/local/bin/sudowrite
export SPELL=/usr/local/bin/sudowrite
Here is how to test it:
sudo touch foo.txt
nano foo.txt
Now write some text and try to save it by typing ctrl + o followed by enter. The following error should appear:
[ Error writing foo.txt: Permission denied ]
Now type ctrl + t followed by y and enter to save the file successfully using the script we wrote above.
Kevin Cox said:
I just use
vim-eunuch which
includes a :SudoWrite
in its list of goodies.
Everything in the plugin is pretty easy to live without but in my mind the simple plugin to have everything on-hand is worth it.
Jen said:
I have got this in my ~/.vimrc now:
command W w !sudo tee "%" > /dev/null
Mario said:
This is a nice tip! I ended up adding this to my ~/.vimrc:
command W execute 'silent write !sudo tee "%" > /dev/null' | edit!
Toby said:
Thanks for the tip! Adding this to my Vim configuration:
com W exe 'sil w !sudo tee "%" > /dev/null' | e!
Long Long said:
Wonderful! I could have done with this trick the number of times I've been caught out with this one. Noted with thanks.