在: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
命令想象成正常 bash 管道情况下的 T 形管道:它将输出定向到指定的文件,并将其发送到标准输出,可以由下一个管道命令捕获。
例如,在 中ps -ax | tee processes.txt | grep 'foo'
,进程列表将被写入文本文件并传递给grep
.
+-----------+ tee +------------+
| | -------- | |
| ps -ax | -------- | grep 'foo' |
| | || | |
+-----------+ || +------------+
||
+---------------+
| |
| processes.txt |
| |
+---------------+
(使用Asciiflow创建的图表。)
有关更多信息,请参见tee
手册页。
T恤作为一个黑客
在您的问题描述的情况下,使用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
部分明确丢弃了标准输出,因为正如我所说,我们不需要将任何内容传递给另一个管道命令。