vim“用sudo编写”技巧如何工作?
你们中许多人可能已经看到了允许你在需要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有人能帮我解析这个命令吗?
%
表示“当前文件”
正如eugene y指出的, %
确实意味着“当前文件名”。 Vim的另一个用途是替代命令。 例如, :%s/foo/bar
表示“ 在当前文件中 ,用bar
替换foo
出现次数。” 如果在键入:s
之前突出显示某些文本,则会看到突出显示的行代替%
作为替代范围。
:w
没有更新您的文件
这个技巧的一个令人困惑的部分是,你可能会认为:w
正在修改你的文件,但它不是。 如果你打开并修改file1.txt
,然后运行:w file2.txt
,那将是一个“另存为”; file1.txt
不会被修改,但当前的缓冲区内容将被发送到file2.txt
。
您可以用shell命令替代 file2.txt
来接收缓冲区内容 。 例如:w !cat
只会显示内容。
如果Vim没有使用sudo访问,它的:w
不能修改受保护的文件,但是如果它将缓冲区内容传递给shell,shell中的命令可以使用sudo运行 。 在这种情况下,我们使用tee
。
理解三通
至于tee
,图片中的tee
命令作为在正常的bash管道情形的T形管:它定向输出到指定的文件(一个或多个),并且也将其发送到标准输出 ,这可以由下一个被捕获管道命令。
例如,在ps -ax | tee processes.txt | grep 'foo'
ps -ax | tee processes.txt | grep 'foo'
ps -ax | tee processes.txt | grep 'foo'
,进程列表将被写入一个文本文件并传递给grep
。
+-----------+ tee +------------+
| | -------- | |
| ps -ax | -------- | grep 'foo' |
| | || | |
+-----------+ || +------------+
||
+---------------+
| |
| processes.txt |
| |
+---------------+
(使用Asciiflow创建图表。)
有关更多信息,请参阅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
部分显式地抛弃了标准输出,因为正如我所说的,我们不需要将任何东西传递给另一个管道命令。
在执行的命令行中, %
代表当前文件名 。 这记录在: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 !sudo tee % > /dev/null
有效地将当前缓冲区的内容作为根文件写入当前文件。 另一个可用于此的命令是dd
:
:w !sudo dd of=% > /dev/null
作为快捷方式,您可以将此映射添加到.vimrc
:
" Force saving files that require root permission
cnoremap w!! w !sudo tee > /dev/null %
使用上面的命令可以输入:w!!<Enter>
以root身份保存文件。
:w
- 写入文件。
!sudo
- 调用shell sudo命令。
tee
- 使用tee重定向的write(vim:w)命令的输出。 %只不过是当前文件名,例如/etc/apache2/conf.d/mediawiki.conf。 换句话说,tee命令是以root身份运行的,它需要标准输入并将其写入由%表示的文件。 但是,这会提示重新加载文件(点击L加载vim中的更改):
教程链接
链接地址: http://www.djcxy.com/p/28611.html