編集後、vimに保存しようとしているファイルが読み取り専用であると報告されることがよくあります。これを回避する方法は、!wq
を追加することです。vimプログラムが読み取り専用ファイルを書き込むための十分な権限を取得できるようにするために、内部で何が行われるのかを理解しようとしていますか?
切り替えられる内部フラグはありますか、またはvimは一時的に一時的に特権を取得しますか?
Vimで_w!
_を実行すると、実際に何が発生するかは、ファイルの所有者によって異なります。
あなた(現在のユーザー)がファイルの所有者である場合、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)
_
これにより、ファイルへのアクセス許可が変更され、書き込み可能になり(chmod()
で使用される_S_IWUSR
_フラグ)、バッファがファイルに書き込まれます。
次に、元の権限を設定します。
_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
_
その他の場合:
最初にファイルのリンクを解除(削除)してから、ファイルを再作成します(ファイルに書き込み、後で権限を変更する前に)。
_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
_
Vimは追加の権限を取得できません。 :w!
は、内部'readonly'
オプションをオーバーライドするだけです。これは、次の理由で設定された可能性があります。
-R
コマンドラインオプションを使用して、または:view
の代わりに:edit
を使用してファイルを開いた、または:setlocal readonly
後者の場合、Vim(デフォルト)が新しいファイルを作成し、元のファイルをそのファイルで置き換えるため、ファイルの書き込みがまだ可能です。これは、これを許可するように設定されている権限に依存します。
Vimを開いたユーザーが何も持っていない場合に実際に書き込み権限を取得するには、直接、または SudoEdit のようなプラグインを通じて:w !Sudo tee >/dev/null file
トリックを使用する必要があります。
書き込み権限のないファイルに書き込むことはできません。ただし、ディレクトリへの書き込み権限がある場合は、そのファイルを削除できます。
VIM=が使用しているトリックは、ファイルを削除して新しいファイルを書き込むことです。
これがメソッドであることを示すことは可能ですVIMソースコードを読み取らずに inode番号 の前後をチェックすることで使用:
$ touch foo
$ chmod u-w foo
$ ls -li foo
60818465 -r--r----- 1 philip philip 0 Feb 25 10:24 foo
$ vi foo
$ # edit the file and save with :w!
$ ls -li foo
60818467 -r--r----- 1 philip philip 8 Feb 25 10:25 foo
Iノード番号が変更され、新しいファイルが編集したファイルと同じでないことを示していることに注意してください。
FYI私の現在の設定は本当に短いです:
runtime! debian.vim
if has("syntax")
syntax on
endif
set tabstop=4
set autoindent
インストールされているdebianパッケージは次のとおりです。
vim 2:8.1.0875-1
vim-common 2:8.1.0875-1
vim-runtime 2:8.1.0875-1
vim-tiny 2:8.1.0875-1
Vimがvi互換モードの場合、:w!は、バッファの読み取り専用モードをオーバーライドするだけですが、ファイルのアクセス許可を前後に変更したり、別のファイルの名前を元の名前に変更してアクセス許可をバイパスしたり、他のアマチュア時間のものを実行したりしません。
これが唯一の正しい動作です私見-これを制御するフラグはW
/cpoptions
からのcpo
です。 :help cpo
から:
*'cpoptions'* *'cpo'* *cpo* 'cpoptions' 'cpo' string (Vim default: "aABceFs", Vi default: all flags) ... *cpo-W* W Don't overwrite a readonly file. When omitted, ":w!" overwrites a readonly file, if possible.
:set compatible
は、すべてのcpo
フラグをオンにします。 :set cpo+=W
またはset cpo-=W
を使用すると、W
フラグのみを変更できます。