一尘不染

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

javascript

你们中的许多人可能已经看到允许您在需要 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有人可以帮我剖析这个命令吗?


阅读 291

收藏
2022-02-21

共1个答案

一尘不染

:w !sudo tee %

%表示“当前文件”

正如eugene y 指出的那样%确实意味着“当前文件名”,它被传递给tee它以便它知道要覆盖哪个文件。

(在替换命令中,它略有不同;如图:help :%所示,它是equal to 1,$ (the entire file)(感谢@Orafu 指出这不会评估文件名)。例如,:%s/foo/bar表示“在当前文件中,将出现的地方foo替换为bar。”如果您突出显示输入之前的一些文本:s,您会看到突出显示的行代替了%您的替换范围。)

:w没有更新您的文件

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

取而代之的是file2.txt,您可以替换为 shell 命令来接收缓冲区内容。例如,:w !cat将只显示内容。

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

了解TEE

至于tee,将tee命令想象成正常 bash 管道情况下的 T 形管道:它将输出定向到指定的文件,并将其发送到标准输出,可以由下一个管道命令捕获。

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

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

(使用Asciiflow创建的图表。)

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

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部分明确丢弃了标准输出,因为正如我所说,我们不需要将任何内容传递给另一个管道命令。

2022-02-21