在:w !sudo tee %
中...
%
指的是“当前文件”
正如eugene y所指出的那样,%
确实意味着“当前文件名”,它会传递给tee
,以便它知道要覆盖哪个文件。
(在替换命令中,略有不同;正如:help :%
所示,它等于1,$(整个文件)(感谢@Orafu指出这并不等于文件名)。例如,:%s/foo/bar
的意思是“在当前文件中,将foo
替换为bar
。” 如果在键入:s
之前突出显示一些文本,则突出显示的行将代替%
作为您的替换范围。)
:w
没有更新您的文件
这个技巧令人困惑的一部分是你可能会认为:w
正在修改你的文件,但它没有。如果您打开并修改了file1.txt
,然后运行:w file2.txt
,它将是一个“另存为”;file1.txt
不会被修改,但当前缓冲区内容将被发送到file2.txt
。
您可以替换一个 shell 命令来接收缓冲区内容。例如,:w !cat
只会显示内容。
如果 Vim 没有以 sudo 权限运行,则它的:w
无法修改受保护的文件,但是如果它将缓冲区内容传递给 shell,则 shell 中的命令将可以使用 sudo 运行。在这种情况下,我们使用tee
。
了解 tee
至于tee
,在正常的 bash 管道情况下,可以将tee
命令想象成一个T形管道:它将输出定向到指定的文件,并将其同时发送到标准输出,后者可以被下一个管道命令捕获。
例如,在ps -ax | tee processes.txt | grep 'foo'
中,进程列表将被写入文本文件并传递给grep
。
+-----------+ tee +------------+
| | -------- | |
| ps -ax | -------- | grep 'foo' |
| | || | |
+-----------+ || +------------+
||
+---------------+
| |
| processes.txt |
| |
+---------------+
(此图是使用 Asciiflow 创建的。)
更多信息请参见tee
man页面。
使用 tee 的 hack 技巧
在您所描述的情况下,使用 tee
是一种 hack 技巧,因为我们忽略了它的一半作用。 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
这部分
明确地丢弃了标准输出,因为我们不需要将任何东西传递给另一个管道命令。
:w!sudo cat >%
是否同样适用,且不会污染标准输出? - Bjarke Freund-Hansensudo
只会应用于cat
命令,而不是>
符号,所以不能通过。你可以尝试在一个sudo
子shell中运行整个命令,例如:w !sudo sh -c "cat % > yams.txt"
,但这也行不通,因为在子shell中,%
是空的,你会清空文件的内容。 - Nathan Long:w !sudo sh -c "cat >%"
的效果与sudo tee %
一样,因为Vim在传递给子shell之前就已经将文件名代替了%
。但是,如果文件名中有空格,两者都不起作用;必须使用:w !sudo sh -c "cat >'%'"
或:w !sudo tee "%"
来解决这个问题。 - Han Seoul-Oh