Sudoでvimを開くのを忘れた場合でも、root権限を必要とするファイルに書き込むことを可能にするコマンドを見たことがあるでしょう。
: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 誰かが私を助けてくれるでしょうか?
:w !Sudo tee %
...
%
は「現在のファイル」を意味しますeugene yが指摘した のように、%
は確かに「現在のファイル名」を意味します。 Vimでこれを使用するもう1つの方法は、置換コマンドです。たとえば、:%s/foo/bar
は、「現在のファイルで、foo
の出現をbar
に置き換えます」を意味します。 :s
を入力する前にテキストを強調表示すると、強調表示された行が置換範囲として%
の代わりになることがわかります。
:w
はファイルを更新していませんこのトリックの紛らわしい部分の1つは、:w
がファイルを変更していると思うかもしれませんが、そうではないということです。 file1.txt
を開いて変更した後、:w file2.txt
を実行すると、「名前を付けて保存」になります。 file1.txt
は変更されませんが、現在のバッファーの内容はfile2.txt
に送信されます。
file2.txt
の代わりに、Shellコマンドを代用してバッファーの内容を受信できます。たとえば、:w !cat
はコンテンツを表示するだけです。
VimがSudoアクセスで実行されなかった場合、その:w
は保護されたファイルを変更できませんが、バッファーの内容をシェルに渡す場合、シェルのコマンド- can Sudoで実行できます。この場合、tee
を使用します。
tee
に関しては、tee
コマンドを通常のbashパイピング状況のT字型パイプとして描きます。指定されたファイルに出力を送信し、も送信しますそれを標準出力に出力します。これは、次のパイプコマンドでキャプチャできます。
たとえば、ps -ax | tee processes.txt | grep 'foo'
では、プロセスのリストがテキストファイルに書き込まれ、がgrep
に渡されます。
+-----------+ tee +------------+
| | -------- | |
| ps -ax | -------- | grep 'foo' |
| | || | |
+-----------+ || +------------+
||
+---------------+
| |
| processes.txt |
| |
+---------------+
( Asciiflow で作成された図。)
詳細については、 tee
manページ を参照してください。
あなたの質問が説明する状況では、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
部分explicitlyは標準出力を破棄します。先ほど言ったように、別のパイプコマンドには何も渡す必要がないからです。 。
実行されたコマンドラインでは、%
は現在のファイル名を表します。これは :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.
すでにご存知のとおり、:w !cmd
は現在のバッファーの内容を別のコマンドにパイプします。 tee
は標準入力を1つ以上のファイルにコピーし、さらに標準出力にもコピーします。したがって、:w !Sudo tee % > /dev/null
は、現在のバッファの内容を現在のファイルrootの間に効率的に書き込みます。これに使用できる別のコマンドは dd
です。
:w !Sudo dd of=% > /dev/null
ショートカットとして、このマッピングを.vimrc
に追加することができます。
" Force saving files that require root permission
cnoremap w!! w !Sudo tee > /dev/null %
上記で、あなたはrootとしてファイルを保存するために:w!!<Enter>
をタイプすることができます。
これもうまく機能します。
:w !Sudo sh -c "cat > %"
これは、@ Nathan Longのコメントに影響されています。
_注意_ :
Shellに渡す前に"
を展開したいので、'
の代わりに%
を使用する必要があります。
:w
- ファイルを書き込みます。
!Sudo
- Shell Sudoコマンドを呼び出します。
tee
- teeを使用してリダイレクトされたwrite(vim:w)コマンドの出力。 %は現在のファイル名、すなわち/etc/Apache2/conf.d/mediawiki.confに他なりません。つまり、teeコマンドはrootとして実行され、標準入力を受け取り、それを%で表されるファイルに書き込みます。しかし、これは再びファイルをリロードするよう促します(Lを押して変更をvim自身にロードします):
受け入れられた答えはそれをすべてカバーするので、私はレコードのために、私が使う shortcut のもう一つの例をあげるでしょう。
それをあなたの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>
は、ここで2つのコマンドを分けるためのpipeシンボルの書き方です。それが役に立てば幸い。他の問題も参照してください。
"ファイルを開いているときにSudo
name__を書くのを忘れたOups"への別のアプローチを提案したいのですが issue:
permission denied
を受け取って:w!!
と入力する代わりに、ファイル所有者がvim
name__の場合はSudo vim
を実行する条件付きroot
name__コマンドを使用するほうがよりエレガントです。
これは実装が簡単です(もっと洗練された実装さえあるかもしれません。私は明らかにbash-guruではありません)。
function vim(){
OWNER=$(stat -c '%U' $1)
if [[ "$OWNER" == "root" ]]; then
Sudo /usr/bin/vim $*;
else
/usr/bin/vim $*;
fi
}
そしてそれは本当にうまくいきます。
これはbash
name __-よりもvim
name __を中心としたアプローチであるため、誰もが気に入らない可能性があります。
もちろん:
root
name__ではないがSudo
name__を必要とするが、関数はとにかく編集することができる場合)vim
name__を使用する場合は意味がありません(私の知る限りでは、小さいファイルにはtail
name__またはcat
name__を使用します)。しかし、これははるかに優れた devユーザーエクスペリエンス をもたらすことがわかりました。これは、bash
name__を使用するときにIMHOが忘れがちなことです。 :-)