你们中的许多人可能都见过这样一个命令,它允许您在需要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;有人能帮我分析一下这个命令吗?


当前回答

公认的答案涵盖了这一切,所以我只举一个我使用的快捷方式的另一个例子,作为记录。

将其添加到etc/vim/vimrc(或~/.vimrc):

cnoremap w!!执行'沉默!写sudo tee%>/dev/null'<bar>edit!

哪里:

cnoremap:告诉vim以下快捷方式将在命令行中关联。w!!:快捷方式本身。执行“…”:执行以下字符串的命令。无声!:安静地运行写sudo tee%>/dev/null:OP问题,添加了将消息重定向为null以生成干净的命令<bar>编辑!:这个技巧是小菜一碟:它还调用edit命令来重新加载缓冲区,然后避免缓冲区已更改等消息<bar>是如何在这里编写管道符号来分隔两个命令。

希望有帮助。其他问题请参见:

超级用户:强制vim写入文件

其他回答

cnoremap w的唯一问题!!就是它用!(并挂起,直到键入下一个字符)!在:命令提示下。就像你想用w!强制保存一样!。此外,即使这不是:之后的第一件事。

因此,我建议将其映射到类似<Fn>w的内容。我个人有mapleader=F1,所以我使用<Leader>w。

用于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!

这将使用ssh-askpass打开一个对话框,询问sudo密码。

我想建议另一种解决“打开文件时忘记写sudo”问题的方法:

而不是接收拒绝的权限,并且必须键入:w!!,我发现如果文件所有者是root,那么使用一个条件vim命令来执行sudovim会更优雅。

这同样容易实现(甚至可能有更优雅的实现,我显然不是bash大师):

function vim(){
  OWNER=$(stat -c '%U' $1)
  if [[ "$OWNER" == "root" ]]; then
    sudo /usr/bin/vim $*;
  else
    /usr/bin/vim $*;
  fi
}

而且效果非常好。

这是一种比vim更以bash为中心的方法,所以不是每个人都喜欢它。

当然:

在某些用例中,它会失败(当文件所有者不是root用户,但需要sudo,但无论如何都可以编辑该函数)当使用vim只读取文件时(就我而言,我对小文件使用tail或cat),这是没有意义的

但我发现这带来了更好的开发用户体验,这是IMHO在使用bash时容易忘记的

公认的答案涵盖了这一切,所以我只举一个我使用的快捷方式的另一个例子,作为记录。

将其添加到etc/vim/vimrc(或~/.vimrc):

cnoremap w!!执行'沉默!写sudo tee%>/dev/null'<bar>edit!

哪里:

cnoremap:告诉vim以下快捷方式将在命令行中关联。w!!:快捷方式本身。执行“…”:执行以下字符串的命令。无声!:安静地运行写sudo tee%>/dev/null:OP问题,添加了将消息重定向为null以生成干净的命令<bar>编辑!:这个技巧是小菜一碟:它还调用edit命令来重新加载缓冲区,然后避免缓冲区已更改等消息<bar>是如何在这里编写管道符号来分隔两个命令。

希望有帮助。其他问题请参见:

超级用户:强制vim写入文件

这也很有效:

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

这是由@Nathan Long的评论引发的。

通知:

必须使用“”而不是“”,因为我们希望%在传递给shell之前被展开。