vim - vim " 写撤销 " 的技巧如何工作?

  显示原文与译文双语对照的内容

许多人可能已经看到了允许你在需要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, 博士可以帮助我剖析这个命令?

时间:

% 表示"当前文件""

就像 eugene指出的%的确意味着"当前文件名"。 Vim中的另一个用途是替换命令。 例如, :%s/foo/bar 意味着"在当前文件,替换出现的foo和bar。"如果你突出显示一些文本输入 :s 之前,你将看到高亮显示的行代替 % 作为替代范围。

:w 没有更新你的文件

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

代替 file2.txt,你可以用替换一个shell命令来接收缓冲区内容。 例如 :wcat 只显示内容。!

如果vim没有运行sudo访问,其 :w 不能修改一个受保护的文件,但是如果它将缓冲区的内容传递给shell,在shell命令可以使用sudo运行。 在本例中,我们使用 tee

了解 tee

对于 tee,在普通bash管道情况下将 tee 命令作为T-shaped管道进行绘制: 它指导输出到指定文件和也将其发送到标准输出,可以捕捉到下一个管道命令。

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


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

( 用 Asciiflow 。) 创建的图表。

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

Tee作为黑客

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

使这个技巧容易

你可以将这里添加到你的.vimrc 中,以使它的成为 easy-to-use: 只需键入 :w 。!


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

The >/dev/null part explicitly throws away standard output, since, as I said, we do not need to pass anything to another piped command.

来自 :help cmdline-special:


In Ex commands, at places where a file name can be used, the following
characters have a special meaning. These can also be used in the expression
function expand().
 % Is replaced with the current file name. :_% c_%
. . .

因此,vim执行的命令 :w!sudo tee current_filename 它获取在vim中编辑的文件的内容,并将它的写入文件,而不是根。

如果你经常使用这里技巧,你可以将这里快捷方式添加到你的。 vimrc:


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

然后使用 w 写入文件。!

:w - 写入文件。

sudo - 调用外壳外壳命令。!

tee - 使用tee重定向写入( vim:w ) 命令的输出。 % 只是当前文件名 换句话说,/etc/apache2/conf. d/mediawiki 。conf 。 换句话说,tee命令作为根运行,它接受标准输入并将它的写入由 %. 代表的文件 但是,这将提示重新加载文件( 点击L 以加载vim本身的更改):

教程链接

这也很正常:


:w!sudo sh -c"cat> %"

这受到 @Nathan 长的评论启发。

通知:

必须使用 " 而不是 ',因为我们希望在传递到shell之前扩展 %

...