你们中的许多人可能都见过这样一个命令,它允许您在需要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;有人能帮我分析一下这个命令吗?
在:w!sudo tee%。。。
%表示“当前文件”
正如尤金y所指出的,%确实意味着“当前文件名”,它被传递给tee,以便它知道要覆盖哪个文件。
(在替换命令中,它稍有不同;例如:help:%shows,它等于1,$(整个文件)(感谢@Orafu指出这不符合文件名)。例如,:%s/foo/bar表示“在当前文件中,用bar替换foo的出现。”如果在键入:s之前高亮显示一些文本,您将看到高亮显示的行将代替%作为替换范围。)
:w未更新您的文件
这个技巧的一个令人困惑的部分是,你可能会认为:w正在修改你的文件,但事实并非如此。如果您打开并修改了file1.txt,然后运行:wfile2.txt,它将是“另存为”;不会修改file1.txt,但当前缓冲区内容将发送到file2.txt。
您可以用shell命令代替file2.txt来接收缓冲区内容。例如: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是一种黑客,因为我们忽略了它的一半功能。sudotee写入文件并将缓冲区内容发送到标准输出,但我们忽略标准输出。在这种情况下,我们不需要将任何内容传递给另一个管道命令;我们只是使用tee作为编写文件的另一种方式,这样我们就可以用sudo调用它。
让这个技巧变得简单
您可以将此添加到.virc中,使此技巧易于使用:只需键入: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!sudotee%>/dev/null有效地将当前缓冲区的内容写入当前文件,同时作为根文件。另一个可用于此操作的命令是dd:
:w !sudo dd of=% > /dev/null
作为快捷方式,您可以将此映射添加到.virc中:
" Force saving files that require root permission
cnoremap w!! w !sudo tee > /dev/null %
使用以上选项,您可以键入:w<输入>将文件保存为根目录。