很多人可能已经看到了允许你在需要root权限的文件上写的命令,即使你忘了用sudo打开vim:
:w !sudo tee %
Run Code Online (Sandbox Code Playgroud)
问题是我不知道这里到底发生了什么.
我已经想到了这个:
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 |:!|.
Run Code Online (Sandbox Code Playgroud)
所以它将所有行作为标准输入传递.
该!sudo tee部件tee使用管理员权限调用.
为了让所有人有意义,%应输出文件名(作为参数tee),但我找不到有关此行为的帮助的参考.
tl; dr有人可以帮我剖析这个命令吗?
Nat*_*ong 1539
在:w !sudo tee %......
% 表示"当前文件"正如eugene指出的那样,%确实意味着"当前的文件名".Vim中的另一个用途是替换命令.例如,tee表示" 在当前文件中,替换:help :%with的出现次数" equal to 1,$ (the entire file).如果在键入之前突出显示某些文本:%s/foo/bar,您会看到突出显示的行代替了foo替换范围.
bar 没有更新您的文件这个技巧的一个令人困惑的部分是你可能认为:s正在修改你的文件,但事实并非如此.如果你打开并修改%,然后运行:w,它将是"另存为"; :w不会被修改,但会将当前缓冲区内容发送给file1.txt.
:w file2.txt您可以替换shell命令来接收缓冲区内容,而不是.例如,file1.txt只显示内容.
如果Vim没有使用sudo访问运行,则它file2.txt无法修改受保护的文件,但如果它将缓冲区内容传递给shell,则可以使用sudo运行shell 中的命令.在这种情况下,我们使用file2.txt.
至于在正常的bash管道情况下:w !cat将:w命令描述为T形管道:它将输出定向到指定的文件,并将其发送到标准输出,可以通过下一个管道命令捕获.
例如,在tee进程中,进程列表将被写入文本文件并传递给tee.
+-----------+ tee +------------+
| | -------- | |
| ps -ax | -------- | grep 'foo' |
| | || | |
+-----------+ || +------------+
||
+---------------+
| |
| processes.txt |
| |
+---------------+
Run Code Online (Sandbox Code Playgroud)
有关详细信息,请参见tee手册页.
在你的问题描述的情况下,使用ps -ax | tee processes.txt | grep 'foo'是一个黑客,因为我们忽略了它的一半.grep写入我们的文件并将缓冲区内容发送到标准输出,但我们忽略标准输出.在这种情况下,我们不需要将任何内容传递给另一个管道命令; 我们只是tee用作编写文件的替代方式,以便我们可以调用它tee.
您可以将此添加到您的使用,sudo tee以使这个技巧易于使用:只需键入tee.
" Allow saving of files as sudo when I forgot to start vim using sudo.
cmap w!! w !sudo tee > /dev/null %
Run Code Online (Sandbox Code Playgroud)
该sudo部分明确地抛弃了标准输出,因为正如我所说,我们不需要将任何东西传递给另一个管道命令.
Eug*_*ash 95
在执行的命令行中,%代表当前文件名.这记录在: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.
Run Code Online (Sandbox Code Playgroud)
正如您已经发现的那样,:w !cmd将当前缓冲区的内容传递给另一个命令.什么tee是将标准输入复制到一个或多个文件,以及标准输出.因此,在root时:w !sudo tee % > /dev/null有效地将当前缓冲区的内容写入当前文件.可用于此的另一个命令是:dd
:w !sudo dd of=% > /dev/null
Run Code Online (Sandbox Code Playgroud)
作为快捷方式,您可以将此映射添加到您的.vimrc:
" Force saving files that require root permission
cnoremap w!! w !sudo tee > /dev/null %
Run Code Online (Sandbox Code Playgroud)
使用上面的内容,您可以键入:w!!<Enter>以root身份保存文件.
fei*_*ihu 19
这也很有效:
:w !sudo sh -c "cat > %"
Run Code Online (Sandbox Code Playgroud)
这是受@Nathan Long评论的启发.
通知:
"必须使用而不是'因为我们希望%在传递给shell之前进行扩展.
可接受的答案涵盖了所有内容,因此,我仅举一个记录所使用的快捷方式的示例。
将其添加到您的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>这里是如何编写管道符号以分隔两个命令的方法。希望能帮助到你。另请参阅其他问题:
对于NEOVIM
由于交互式调用的问题(https://github.com/neovim/neovim/issues/1716),我根据Beco博士的回答将其用于neovim:
cnoremap w!! execute 'silent! write !SUDO_ASKPASS=`which ssh-askpass` sudo tee % >/dev/null' <bar> edit!
Run Code Online (Sandbox Code Playgroud)
这将打开一个对话框,ssh-askpass询问 sudo 密码。
我想提出另一种方法来解决“ sudo打开文件时忘记写的操作”问题:
我发现有一个条件命令(如果文件所有者为的话)可以代替它permission denied,而不是必须输入。:w!!vimsudo vimroot
这很容易实现(甚至可能会有更优雅的实现,我显然不是bash专家):
function vim(){
OWNER=$(stat -c '%U' $1)
if [[ "$OWNER" == "root" ]]; then
sudo /usr/bin/vim $*;
else
/usr/bin/vim $*;
fi
}
Run Code Online (Sandbox Code Playgroud)
而且效果很好。
这是一种bash比vim- 更加集中的方法,因此并非每个人都喜欢它。
当然:
root但需要时sudo,但该功能仍可以编辑) vim用于只读文件时没有任何意义(就我而言,我使用的tail还是cat小文件)但是我发现这带来了更好的开发用户体验,而IMHO在使用时往往会被遗忘bash。:-)
| 归档时间: |
|
| 查看次数: |
345655 次 |
| 最近记录: |