很多人可能已经看到了允许你在需要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 有人可以帮我剖析这个命令吗?
6 回答
在
:w !sudo tee %
......%表示“当前文件”
如eugene y pointed out,
%
的确意味着"the current file name" . Vim中的另一个用途是替换命令 . 例如,:%s/foo/bar
表示“ in the current file ,用bar
替换foo
的出现次数” . 如果在键入:s
之前突出显示某些文本,您会看到突出显示的行代替%
作为替换范围 .:w未更新您的文件
这个技巧的一个令人困惑的部分是你可能认为
:w
正在修改你的文件,但事实并非如此 . 如果您打开并修改了file1.txt
,那么运行:w file2.txt
,它将是"save as";file1.txt
不会被修改,但当前缓冲区内容将被发送到file2.txt
.而不是
file2.txt
,你可以 substitute a shell command to receive the buffer contents . 例如,:w !cat
将只显示内容 .如果Vim没有使用sudo访问运行,则
:w
无法修改受保护的文件,但如果它将缓冲区内容传递给shell,则为 a command in the shell can be run with sudo . 在这种情况下,我们使用tee
.了解发球台
至于
tee
,在正常的bash管道情况下将tee
命令描述为T形管道:它将输出定向到指定的文件和 also sends it to standard output ,可以通过下一个管道命令捕获 .例如,在
ps -ax | tee processes.txt | grep 'foo'
中,进程列表将写入传递给grep
的文本文件 and .(使用Asciiflow创建的图表 . )
有关详细信息,请参阅tee man page .
Tee as a hack
在您的问题描述的情况下, using tee is a hack because we're ignoring half of what it does .
sudo tee
写入我们的文件,并将缓冲区内容发送到标准输出,但 we ignore standard output . 我们只是使用tee
作为编写文件的替代方式,以便我们可以使用sudo
来调用它 .轻松搞定这个伎俩
您可以将此添加到
.vimrc
以使此技巧易于使用:只需键入:w!!
即可 .> /dev/null
部分 explicitly 会抛弃标准输出,因为正如我所说,我们不需要将任何内容传递给另一个管道命令 .在执行的命令行中,
%
代表 current file name . 这在:help cmdline-special中记录:正如您已经发现的那样,
:w !cmd
将当前缓冲区的内容传递给另一个命令 . tee的作用是将标准输入复制到一个或多个文件,还复制到标准输出 . 因此,:w !sudo tee % > /dev/null
有效地将当前缓冲区的内容写入当前文件 while being root . 可用于此的另一个命令是dd:作为快捷方式,您可以将此映射添加到
.vimrc
:使用上面的内容,您可以键入
:w!!<Enter>
以root身份保存文件 .这也很有效:
这是受@Nathan Long评论的启发 .
NOTICE :
必须使用
"
而不是'
,因为我们希望在传递给shell之前扩展%
.:w
- 写一个文件 .!sudo
- 调用shell sudo命令 .tee
- 使用tee重定向的write(vim:w)命令的输出 . %只是当前文件名,即/etc/apache2/conf.d/mediawiki.conf . 换句话说,tee命令以root身份运行,它接受标准输入并将其写入由%表示的文件 . 但是,这将提示再次重新加载文件(点击L加载vim本身的更改):tutorial link
接受的答案涵盖了所有内容,因此我将再举一个我使用的 shortcut 的例子作为记录 .
将其添加到
etc/vim/vimrc
(或~/.vimrc
):cnoremap w!! execute 'silent! write !sudo tee % >/dev/null' <bar> edit!
哪里:
cnoremap
:告诉vim命令行中将关联以下快捷方式 .w!!
:快捷方式本身 .execute '...'
:执行以下字符串的命令 .silent!
:静默运行write !sudo tee % >/dev/null
:OP问题,添加了一条消息重定向到NULL
以进行干净的命令<bar> edit!
:这个技巧是蛋糕的樱桃:它还调用edit
命令重新加载缓冲区,然后避免缓冲区等消息发生变化 .<bar>
是如何编写管道符号以在此处分隔两个命令 .希望能帮助到你 . 另见其他问题:
我想建议另一种方法来解决“Oups我忘了写
sudo
同时打开我的文件”问题:而不是收到
permission denied
,并且必须输入:w!!
,如果文件所有者是root
,我发现如果有一个条件vim
命令可以执行sudo vim
更为优雅 .这很容易实现(甚至可能有更优雅的实现,我显然不是bash-guru):
它的效果非常好 .
这是一个比
vim
更为中心的方法,因此不是每个人都喜欢它 .当然:
有些用例会失败(当文件所有者不是
root
但需要sudo
时,但无论如何都可以编辑该功能)使用
vim
只读文件时没有意义(就我而言,我使用tail
或cat
作为小文件)但是我发现这会带来更好的 dev user experience ,这是恕我直言,当使用
bash
时往往会被遗忘 . :-)