Vimでシェルコマンドの出力をバッファに直接挿入する(:r!)
ターミナルでlsを実行して、その結果をコピーしてVimに貼り付ける、という作業を繰り返していました。コマンドの実行結果を直接バッファに挿入するコマンドがあり、コピペの手間そのものがいらなくなります。
目次(10項目)
| キー | これだけ覚える |
|---|---|
:r!{コマンド} | コマンドの出力をバッファに挿入 |
:!{コマンド} | 結果を画面に表示するだけ(バッファには残らない) |
:new | 新規バッファを開いてから読み込む |
コマンドの実行結果を挿入する
:r!{コマンド}
:r(:read)はファイルの内容をバッファに読み込むコマンドですが、続けて!とコマンドを書くと、ファイルの代わりにコマンドの実行結果をそのまま挿入してくれます。カーソル行の下に結果が挿入されます。
line 1
line 2
:r!echo hiline 1
hi
line 2
よく使う場面
:r!ls " カレントディレクトリのファイル一覧を挿入(Linux/Mac)
:r!dir " 同上(Windows)
:r!pwd " カレントディレクトリのフルパスを挿入
設定ファイルにファイル一覧を書き出したいときや、スクリプトの中に現在のパスをハードコードしたいときなど、「今いる場所の情報をそのままテキストとして取り込みたい」場面で特に役立ちます。dateコマンドで現在時刻を挿入したり、git log --oneline -5で直近のコミット一覧を挿入したりと、応用範囲は広いです。
カーソル位置に注意する
挿入先はカーソルのある行の下です。意図しない場所に挿入してしまわないよう、実行前にカーソル位置を確認しておくと安心です。挿入した直後の内容が気に入らなければ、通常どおりuでアンドゥできるので、試しに実行してから調整する使い方でも問題ありません。
:!との違い
:!{コマンド}は結果を画面に表示するだけで、バッファには何も残りません。一方:r!{コマンド}はその結果をテキストとしてバッファに書き込みます。「見るだけでいいのか、テキストとして残したいのか」で使い分けると便利です。コマンド実行全般の使い分けは別記事にまとめています。
:!、テキストとしてバッファに取り込みたいなら:r!。コピペの手間を1コマンドで省けます。
ディレクトリ構成をREADMEに書き出す作業で、毎回lsの結果を手でコピペしていましたが、:r!lsを知ってからはその手間がまるごと消えました。地味なコマンドですが、ドキュメント作成やスクリプトの雛形作りをする機会が多い人ほど積み重なる時短効果は大きいと感じています。挿入位置を間違えてもuで戻せると分かってからは、気軽に試せるようになりました。
新規バッファに読み込みたい場合
今編集中の内容とは別に、コマンドの結果だけをまっさらなバッファで見たいときは、先に:newで新しいバッファを開いてから:r!を実行すると安心です。既存の内容を汚さずに済むので、探索的にコマンドの出力を確認したいときや、結果を見ながら必要な部分だけ元のファイルにコピーしたいときに向いています。
:new
:r!git log --oneline -10
挿入する位置を数字で決める
カーソル位置を気にせず挿入したいときは、行番号を前に付けます。0 はファイルの先頭より前、$ は最終行の後ろです。
:0r !date +\%Y-\%m-\%d " ファイルの先頭に挿入
:$r !git log --oneline -5 " ファイルの末尾に挿入
:10r !ls " 10行目の下に挿入
コマンドラインでは % が「開いているファイル名」に展開されるので、date の書式指定のように % を含むコマンドでは \% と打ち消す必要があります。実行してファイル名が混ざったら、これを忘れています。
出力の文字コードと改行
外部コマンドの出力がUTF-8以外の場合、挿入した部分だけが化けます。読み込み時の文字コードは ++enc= で指定できます。
:r ++enc=cp932 !dir " Windows のコマンド出力を読む
改行コードも同じで、Windowsのコマンドの出力には ^M が付くことがあります。挿入したあとに :'[,']s/\r$// と打てば、いま挿入した範囲だけから消せます。'[ と '] は直前に挿入した範囲の先頭と末尾を指すマークです。
出力が大きいとき
数万行を返すコマンドをそのまま挿入すると、Vimが固まったように見える時間が長く続きます。挿入する前に head や grep で絞るか、いったんファイルに落としてから開くほうが確実です。
:r !find . -name '*.log' | head -50
:!find . -name '*.log' > /tmp/list.txt
:e /tmp/list.txt
実行を待たされたくないなら :terminal で走らせて、必要な部分だけをコピーする方法もあります。シェルコマンドの実行で使い分けを扱っています。
まとめ
:r!はシェルコマンドの出力をそのままテキストとしてバッファに取り込めます。コピペの手間を減らしたいなら覚えておいて損はないコマンドです。