vim 如何覆盖只读模式?

Atu*_*tul 26 shell vim

我们经常看到我们在编辑后尝试在 vim 中保存的文件被报告为只读。解决这个问题的方法是添加!wq,我试图弄清楚内部是什么允许 vim 程序获得足够的权限来写入只读文件?

是否有内部标志被切换或 vim 暂时获得了一段时间的特权?

Kus*_*nda 26

当您w!在 Vim 中进行操作时,实际发生的情况取决于谁拥有该文件。

  • 如果您(当前用户)是文件的所有者,Vim 将在重写文件之前将权限更改为可写。然后它删除写权限以将权限位恢复到从一开始的状态。

  • 如果您不是该文件的所有者,但如果您在当前目录中有写权限,Vim 将删除原始文件并将该文档写入一个同名的新文件中。新文件将被分配与原始文件相同的权限,但归您所有。

Vim 永远不会获得能够写入文件的提升权限。

上述机制是任何需要写入只读文件的程序都必须选择的可用选项(即在写入文件时临时更改权限,或删除文件并创建一个新文件),以及Vim 最终选择做什么可能取决于许多可配置的设置。

正如在下面的评论中看到的那样,上述内容存在一些混淆。如果您想亲眼看看在您的特定品牌的 Unix 上设置 Vim 时实际发生了什么,我建议您跟踪 Vim 在写入只读文件时所做的系统调用。这是如何完成的取决于您使用的是什么 Unix。在 Linux 上,这可能是通过例如strace vim file(然后编辑文件,保存w!并退出)来完成的。


这是第一种情况(从OpenBSD 上的ktrace+输出kdump):

13228 vim      CALL  chmod(0x19b1d94b4b10,0100644<S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH|S_IFREG>)
13228 vim      NAMI  "file"
13228 vim      RET   chmod 0
13228 vim      CALL  lseek(3,0x1000,SEEK_SET)
13228 vim      RET   lseek 4096/0x1000
13228 vim      CALL  write(3,0x19b1e0aa9000,0x1000)
Run Code Online (Sandbox Code Playgroud)

这会更改文件的权限,使其可写(与 一起S_IWUSR使用的标志chmod())并将缓冲区写入其中。

然后设置原始权限:

13228 vim      CALL  fchmod(4,0100444<S_IRUSR|S_IRGRP|S_IROTH|S_IFREG>)
13228 vim      RET   fchmod 0
13228 vim      CALL  close(4)
13228 vim      RET   close 0
Run Code Online (Sandbox Code Playgroud)

对于另一种情况:

它首先取消链接(删除)文件,然后重新创建它(在写入文件并稍后更改权限之前):

44487 vim      CALL  unlink(0x79fdbc1f000)
44487 vim      NAMI  "file"
44487 vim      RET   unlink 0
44487 vim      CALL  open(0x79fdbc1f000,0x201<O_WRONLY|O_CREAT>,0644<S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH>)
44487 vim      NAMI  "file"
44487 vim      RET   open 4
Run Code Online (Sandbox Code Playgroud)


Ing*_*kat 5

Vim 无法获得额外的权限。只是:w!覆盖了内部'readonly'选项,该选项的设置可能是因为:

  • -R您已通过命令行选项打开该文件或:view使用:edit, 或:setlocal readonly
  • Vim 识别出该文件当前没有写权限

对于后一种情况,文件写入仍然是可能的,因为 Vim(默认情况下)创建一个新文件,然后用它替换原始文件。这仍然取决于以允许这样做的方式设置的权限。


要真正获得打开 Vim 的用户没有的写入权限,:w !sudo tee >/dev/null file必须直接使用该技巧,或通过SudoEdit等插件使用。