pockestrap

Programmer's memo

bash, zshで挙動が違う、そして謎

a='ls -l'
$a

これ、実行するとどうなると思いますか?


bashでは

drwxr-xr-x  2 pocke users   4096  6月 14 20:13 Desktop
drwxr-xr-x  8 pocke users   4096 10月 25 10:47 Document
drwxr-xr-x 15 pocke users   4096 11月 18 21:13 Download
....

みたいに出力されます。
対してzshでは

zsh: command not found: ls -l

と言われてしまいます。つまり、zshでは変数aの内容全てがコマンドとして解釈され、一方bashでは-lがオプションとして解釈されています。
なお、bashでも

a='ls -l'
"$a"

と、明示的に変数aを文字列として評価してやれば

bash: ls -l: command not found

と言わせることができます。(ダブルクオートで囲んだ場合、zshでも挙動は変わらない)


これならば、「zshだと変数は文字列として評価されて、bashだとスペースで区切られて評価されるんだなー」って感じに思うのですが、次の場合がよくわからなかった。

a='ls -l && ls -a'
$a

これをbashで実行すると、

ls: cannot access &&: No such file or directory
ls: cannot access ls: No such file or directory

と言われてしまいます。
およよ…どうやら後ろの文字列は引数として評価されるみたいですね。

シェルスクリプト、よくわかんないよなぁ……。
ちなみに$aの内容を実行したいなら、

a='ls -l && ls -a'
eval $a

みたいにすればよいとおもいますー。

2013/12/07 追記
どうやら、ひとつの文字列で展開されるのはzshの仕様みたいです。

${=a}

と変数展開の際に=を入れてやると、空白で分割されたものが展開されるようです。