おそらく皆さんの多くは、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誰かこのコマンドを分析するのを手伝ってくれませんか?
ベストアンサー1
で:w !sudo tee %
...
%
「現在のファイル」を意味します
としてユージン・Yは指摘したは、実際には「現在のファイル名」を意味し、どのファイルを上書きするかを認識できるように%
渡されます。tee
(置換コマンドでは、少し異なります。:help :%
示されているように、 ですequal to 1,$ (the entire file)
(ファイル名に評価されないことを指摘してくれた @Orafu に感謝します)。 たとえば、 は「現在のファイル で、の出現を に置き換える」:%s/foo/bar
という意味です。 と入力する前にテキストをハイライトすると、 がハイライトされた行に置き換わって置換範囲として使用されることがわかります。)foo
bar
:s
%
:w
ファイルが更新されていません
:w
このトリックの紛らわしい部分は、 がファイルを変更すると思うかもしれないが、そうではないということです。 を開いて変更しfile1.txt
、 を実行した場合:w file2.txt
、それは「名前を付けて保存」となり、 はfile1.txt
変更されませんが、現在のバッファの内容が に送信されますfile2.txt
。
の代わりに、シェル コマンドを使用してバッファの内容を受け取ることfile2.txt
ができます。たとえば、は内容を表示するだけです。:w !cat
Vim が sudo アクセスで実行されていない場合、:w
保護されたファイルを変更することはできませんが、バッファの内容をシェルに渡すと、シェル内のコマンドをsudo で実行できます。この場合は を使用しますtee
。
ティーを理解する
については、通常の bash パイプの状況で、コマンドを T 字型のパイプとしてtee
考えてください。このコマンドは、出力を指定されたファイルに送信するとともに、標準出力にも送信します。この標準出力は、次のパイプ コマンドによってキャプチャできます。tee
たとえば、 ではps -ax | tee processes.txt | grep 'foo'
、プロセスのリストがテキスト ファイルに書き込まれ、に渡されますgrep
。
+-----------+ tee +------------+
| | -------- | |
| ps -ax | -------- | grep 'foo' |
| | || | |
+-----------+ || +------------+
||
+---------------+
| |
| processes.txt |
| |
+---------------+
(図はアスキーフロー。
を参照してくださいtee
マニュアルページ詳細については。
ティーをハックとして
質問で説明されている状況では、を使用することtee
はハックです。なぜなら、 の機能の半分を無視しているからです。sudo tee
はファイルに書き込み、バッファの内容を標準出力に送信しますが、標準出力は無視します。 この場合、別のパイプ コマンドに何かを渡す必要はありません。 をファイルへの書き込みの代替方法として使用しているだけなのでtee
、 で呼び出すことができますsudo
。
このトリックを簡単にする
これを に追加すると、.vimrc
このトリックが使いやすくなります。 と入力するだけです:w!!
。
" Allow saving of files as sudo when I forgot to start vim using sudo.
cmap w!! w !sudo tee > /dev/null %
前述したように、パイプされた別のコマンドに何も渡す必要がないため、この> /dev/null
部分では標準出力を明示的に破棄します。