vim“用sudo编写”技巧如何工作?

你们中许多人可能已经看到了允许你在需要root权限的文件上编写的命令,即使你忘记用sudo打开vim:

:w !sudo tee %

问题是我没有得到这里发生的事情。

我已经明白了这一点: w是为了这个

                                                        *: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 |:!|.

所以它将所有行作为标准输入。

!sudo tee部分以管理员权限呼叫tee

为了让所有人理解, %应输出文件名(作为tee的参数),但我无法找到有关此行为的帮助的参考。

tl; dr有人能帮我解析这个命令吗?


%表示“当前文件”

正如eugene y指出的, %确实意味着“当前文件名”。 Vim的另一个用途是替代命令。 例如, :%s/foo/bar表示“ 在当前文件中 ,用bar替换foo出现次数。” 如果在键入:s之前突出显示某些文本,则会看到突出显示的行代替%作为替代范围。

:w没有更新您的文件

这个技巧的一个令人困惑的部分是,你可能会认为:w正在修改你的文件,但它不是。 如果你打开并修改file1.txt ,然后运行:w file2.txt ,那将是一个“另存为”; file1.txt不会被修改,但当前的缓冲区内容将被发送到file2.txt

您可以用shell命令替代 file2.txt 来接收缓冲区内容 。 例如:w !cat只会显示内容。

如果Vim没有使用sudo访问,它的:w不能修改受保护的文件,但是如果它将缓冲区内容传递给shell,shell中的命令可以使用sudo运行 。 在这种情况下,我们使用tee

理解三通

至于tee ,图片中的tee命令作为在正常的bash管道情形的T形管:它定向输出到指定的文件(一个或多个),并且也将其发送到标准输出 ,这可以由下一个被捕获管道命令。

例如,在ps -ax | tee processes.txt | grep 'foo' ps -ax | tee processes.txt | grep 'foo' ps -ax | tee processes.txt | grep 'foo' ,进程列表将被写入一个文本文件传递给grep

     +-----------+    tee     +------------+
     |           |  --------  |            |
     | ps -ax    |  --------  | grep 'foo' |
     |           |     ||     |            |
     +-----------+     ||     +------------+
                       ||   
               +---------------+
               |               |
               | processes.txt |
               |               |
               +---------------+

(使用Asciiflow创建图表。)

有关更多信息,请参阅tee手册页。

作为黑客的开球

在你的问题描述的情况下, 使用tee是一种破解,因为我们忽略了它的一半sudo tee写入我们的文件并将缓冲区内容发送到标准输出,但我们忽略了标准输出 。 在这种情况下,我们不需要将任何东西传递给另一个管道命令; 我们只是使用tee作为编写文件的替代方式,因此我们可以使用sudo来调用它。

使这个窍门容易

您可以将其添加到您的.vimrc以使此技巧易于使用:只需键入:w!!

" Allow saving of files as sudo when I forgot to start vim using sudo.
cmap w!! w !sudo tee > /dev/null %

> /dev/null部分显式地抛弃了标准输出,因为正如我所说的,我们不需要将任何东西传递给另一个管道命令。


在执行的命令行中, %代表当前文件名 。 这记录在: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.

正如你已经发现的那样, :w !cmd将当前缓冲区的内容传送给另一个命令。 tee所做的是将标准输入复制到一个或多个文件,也复制到标准输出。 因此, :w !sudo tee % > /dev/null有效地将当前缓冲区的内容作为根文件写入当前文件。 另一个可用于此的命令是dd

:w !sudo dd of=% > /dev/null

作为快捷方式,您可以将此映射添加到.vimrc

" Force saving files that require root permission 
cnoremap w!! w !sudo tee > /dev/null %

使用上面的命令可以输入:w!!<Enter>以root身份保存文件。


:w - 写入文件。

!sudo - 调用shell sudo命令。

tee - 使用tee重定向的write(vim:w)命令的输出。 %只不过是当前文件名,例如/etc/apache2/conf.d/mediawiki.conf。 换句话说,tee命令是以root身份运行的,它需要标准输入并将其写入由%表示的文件。 但是,这会提示重新加载文件(点击L加载vim中的更改):

教程链接

链接地址: http://www.djcxy.com/p/28611.html

上一篇: How does the vim "write with sudo" trick work?

下一篇: Python Lambda in a loop