この記事は Vim Advent Calendar 2016 (その2) の3日目の記事です。
UNIXのテキスト処理
UNIXでテキストを自動整形する際、パイプ機能は欠かせない。
$ cat a.txt 1 hoge 2 piyo 3 fuga $ cat a.txt |sed 's/piyo/foo/' |grep '2' 2 foo
シェル上で |
というパイプ記号を使ってコマンドを次々繋げることで、複雑なテキスト処理をこなすわけだ。
パイプは便利だが、テキストエディタをパイプとして使う人はあまり見かけない。
テキストエディタ=対話的 という常識があるため、パイプのような自動処理とは相性が悪いと思われているのだろう。
しかし今日はあえて、シェルスクリプトやワンライナーの中にvimを埋め込み、パイプとして静的に使ってみたい。
vimをパイプとして使う
vimを普通に使って冒頭の$ cat a.txt |sed 's/piyo/foo/'
を行うには、ノーマルモードでjwCfoo
と入力すればよい。
このjwCfoo
という呪文をシェル上で使用するには以下のようにすれば良い。
# 最も普通の方法 $ cat a.txt |vim -es +'norm jwCfoo' +%p +q! /dev/stdin # あるいは $ cat a.txt |ex -s +'norm jwCfoo' +%p +q! /dev/stdin # このやり方は Vim: Reading stdin... 問題が生じる $ cat a.txt |vim - -es +'norm jwCfoo' +%p +q! |sed '1d'
とすればよい。一番上のワンライナーの説明をしておくと
vim -e
はex
と等価で、vimを非対話(exモード)で起動するという意味。-s
はサイレントモードで起動し、標準出力を汚さないというオプション。+'norm jwCfoo'
のnorm
は、ノーマルモードのコマンドを使うという意味。jwCfoo
はvimの呪文。中にESCを入れるにはCtrl+vしてESCを押す。+%p
はファイルの全内容を標準出力に表示するexコマンド。+q!
はvimを強制終了するexコマンド。馴染み深い。/dev/stdin
は読み込み先を標準入力 (cat a.txt) にするという意味。
三番目のワンライナーは/dev/stdin
の代わりにハイフン(標準入力のシンボル)を使っていて、スマートに見える。
ただしこの方法では、標準出力の冒頭にVim: Reading from stdin...
というクッソうざい文字列が勝手に挿入される。
こいつを消すには、直後にシェルコマンド|sed '1d'
等を噛ます必要がある。
外部コマンドにしよう
以下のようなvipeコマンドを作っておくと、シェル上でvimの呪文が使いやすくなる。
# .bashrcや.zshrcに書き込む vipe () { # コロン':'でESC入力を代替する場合はコメントを外す。^[はCtrl+vしてESC押して入力 # COMMAND=$(echo "$*" |sed -e 's/:/^[/g') vim - -es +":norm gg" +":norm $COMMAND" +:%p +:q! |sed '1d' }
使い方は以下のような感じ。
$ cat a.txt 1 hoge 2 piyo 3 fuga $ cat a.txt |vipe jwCfoo |grep '2' 2 foo # ^[はESC文字で、Ctrl+Vした後にESCを押して入力する $ cat a.txt |vipe Abar^[oxxxx 1 hogebar xxxx 2 piyo 3 fuga # コマンドに空白文字を含む場合は'か"でくくる $ cat a.txt |vipe "A bar baz" 1 hoge bar baz 2 piyo 3 fuga
シェル上でvimのマクロ機能を使う
vimには超便利なマクロ機能が存在する。
簡単に説明すると、ノーマルモードにおける一連の操作をマクロ文字列として記録再生する機能で、
qa
と押すことでレジスタaに記録し、@a
と押すことで再生できる。
上述のjwCfoo
という呪文はvimのマクロの一種といえるだろう。
vimを対話的に使って (qa
を使って) 記録したマクロを表示するには、ノーマルモードで"ap
と押せば良い。
こうして表示されたレジスタaの中身は、vipeコマンドの引数として食わせることが出来る。
$ cat a.txt |vipe "レジスタの中身を書き込む"
これで「vimのマクロを使いまわしたいな〜」なんて場合も安心ですね!
参考
vim -es
とした時に表示されるVim: Reading from stdin...
問題についてはコチラ。
vimのソースコードを修正してくれ~