この記事はVim Advent Calendar 2012 : ATND231日目の記事になります。
昨日の記事は@ujihisaさんのVim script初心者用入門記事でした。
なので、今回はVim scripterになると必ずお世話になるだろうvimproc.vim、
具体的にはvimproc#system({expr})
の{expr}の展開のされ方について説明します。
この記事で語ることは、基本的にvimproc#system()
でのみで確認しています。vimproc#system_bg()
などでも同じ展開のされ方になると思いますが(たぶん)、
未確認なのでご了承ください。
以下のVim環境で確認しています。
- Windows7 Pro SP1 64bit
- VIM - Vi IMproved 7.3 MS-Windows 32-bit GUI version Included patches: 1-966
set shell=C:\Windows\System32\cmd.exe
set noshellslash
- vimproc:
c7bada0
{expr}の展開の流れ
vimproc#system({expr})
の{expr}に指定された文字列は大まかに以下の順番で展開されます。
(実際にはもうちょっと複雑で、以下の通りではありません。が、処理は以下のようなことが処理されています。)
- コメント除去
複数のステートメントに分解する(アンパサンド、パイプ、セミコロン)
特殊文字を展開する
- ブロック
- チルダ
- 実行コマンドパス
- 変数
- ワイルドカード
- チルダ
コメント除去
複数のステートメントに分解する(リダイレクト)
各ステートメントの実行
ただし、文字が以下に当てはまる場合には上記とは異なる扱いになります。
- シングルクォート内の文字
- ダブルクォート内の文字
- バッククォート内の文字
- エスケープされている文字
それぞれの説明
コメント除去
#
以降の文字列はすべてコメントととして扱われます。
echo vimproc#system('echo hello # world!')" hello
echo vimproc#system('echo hello $HOGE world!')" $HOGEが'#'のとき" hello
echo vimproc#system('echo hello # world $HOGE hoge')" $HOGEが'#'のとき" hello
複数のステートメントに分解する(アンパサンド、パイプ、セミコロン)
vimprocは&&
、||
、;
によって複数のステートメントだと認識します。
もし変数に'&&'
などが入っている場合、vimprocは1つのステートメントだと認識します。
(この場合の'&&'
の処理は処理系に依存します)
また、vimprocは&
と|
を単なる文字列として認識します(これも処理系に依存しますね)。
echo vimproc#system('echo hello && echo world')" hello " world
echo vimproc#system('echo hello || echo world')" world
echo vimproc#system('echo hello ; echo world')" hello" world
echo vimproc#system('echo hello $HOGE echo world')" $HOGEが'&&'のとき" hello " world
特殊文字を展開する
ブロック
vimprocはブロックという値リストのようなものをサポートしています。
(:h vimshell-tips-block
を参照)
echo vimproc#system('echo /bin/{cd,ls}')" /bin/cd /bin/ls
echo vimproc#system('echo {0..9}')" 00 01 02 03 04 05 06 07 08 09
echo vimproc#system('echo {00..09}')" 000 001 002 003 004 005 006 007 008 009
echo vimproc#system('echo {0..3}-{0..3}')" 0..3}-{0..3
echo vimproc#system('echo /bin/$HOGE')" $HOGEが'{cd,ls}'のとき" /bin/{cd,ls}
チルダ
~
を$HOME
の値に置換します。(チルダの前のスペースも必要!)
echo vimproc#system('echo ~')" C:/Users/rbtnn
echo vimproc#system('echo a~')" a~
実行コマンドパス
=
に続くコマンド文字列をそのコマンドのパスに置換します。(イコールの前のスペースも必要!)
echo vimproc#system('echo =cmd')" C:/Windows/SysWOW64/cmd.exe
echo vimproc#system('echo =ls')" C:/Git/bin/ls.exe
echo vimproc#system('echo =ls hello')" C:/Git/bin/ls.exe hello
https://github.com/Shougo/vimproc.vim/pull/68要参照
変数
環境変数を展開します。
echo vimproc#system('echo $HOME')" C:/Users/rbtnn
ワイルドカード
vimprocは3種類のワイルドカード(*
,?
,[]
)をサポートしています。
(:h vimshell-tips-wildcard
を参照)
echo vimproc#system('echo ~/ntuser.dat.????')" C:/Users/rbtnn/ntuser.dat.LOG1 C:/Users/rbtnn/ntuser.dat.LOG2
echo vimproc#system('echo ~/.vim[a-z]c')" C:/Users/rbtnn/.vimrc
echo vimproc#system('echo ~/.git*')" C:/Users/rbtnn/.git C:/Users/rbtnn/.gitconfig C:/Users/rbtnn/.gitconfig.local C:/Users/rbtnn/.gitignore
複数のステートメントに分解する(リダイレクト)
vimprocは5種類のリダイレクト(<
,1>
,2>
,>&
,>>
)をサポートしています。
シングルクォート
vimprocはシングルクォート内のシングルクォートを''
で表すことができます。変数は展開されません。
echo vimproc#system("echo 'He''s a student.'")" "He's a student."
ダブルクォート
vimprocはダブルクォート内で特定の文字をエスケープすることができ、以下のような辞書(escape_sequences
)にて変換が行われます。変数は展開されます。
let escape_sequences = {
\ 'a' : "\<C-g>",'b' : "\<BS>",
\ 't' : "\<Tab>",'r' : "\<CR>",
\ 'n' : "\<LF>",'e' : "\<Esc>",
\ '\' : '\', '?' : '?',
\ '"' : '"',"'" : "'",
\ '`' : '`','$' : '$',
\}
echo vimproc#system('echo "hoge\nfoo"')" fooが出力されなかった。バグ?" hoge"
echo vimproc#system('echo "hoge\tfoo"')" hoge foo
echo vimproc#system('echo "\$HOHE"')" $HOHE
echo vimproc#system('echo "$HOME"')" C:/Users/rbtnn
バッククォート
vimprocはバッククォート内にコマンドもしくはVim script式を入れて評価した結果を展開することができます。
(:h vimshell-tips-backquote
を参照)
echo vimproc#system('echo `git --version`')" git version 1.8.1.msysgit.1
echo vimproc#system('echo `=3`')" Vim script式" 3
echo vimproc#system('echo `=3*&columns`')" Vim script式" 510
エスケープ
vimprocはクォート外では以下の4つの文字をエスケープ出来ます。
echo vimproc#system('echo \\')" \
echo vimproc#system('echo \''')" '
echo vimproc#system('echo \"')" "\""
echo vimproc#system('echo \`')" `
以上、「vimproc#system({expr})
の{expr}の展開のされ方」でした。
vimproc.vimは暗黒美夢王さんのプロダクトなのでvimshell.vimの挙動そのままですね。
明日の記事は@deris0126さんです。