Diff of UNIX/コマンド/シェル・シェル組み込み/eval


TITLE:eval - コマンドを実行
#navi(UNIX/コマンド)

引数とした文字列をコマンドと解釈して実行します。

#contentsx

*例 [#he00a22a]

たとえば
 % eval cd /
とすれば cd / を実行します。"cd /" のようにしたほうが安全かもしれません。
引数の文字列は複数個でもかまいません。連結して実行されます。

正確にはevalは引数を一度「評価」し、それらを改めてコマンドとして実行します。「評価」とは変数を展開することです。

 % set x='ls -d $HOME' (csh, tcsh の場合)
 % $x
 ls: $HOME: No such file or directory
 
シングルクォーテーションの場合、変数は展開されずに格納されるため、
$HOME という文字として扱われている。

 % eval $x
 /home/student/s1080134

$HOME を展開してくれている。

このように、文字列を評価しコマンドを実行する eval は、シェルに限らずC言語など様々な言語で採用されているので覚えてよくと便利な時がきっと来ます。
*シェルスクリプト内での使用 [#y56f8cda]
eval は基本的にはシェルスクリプト内で使います。

 #!/bin/bash
 num=1
 while [ $num -le $# ] ; do
    eval echo "Argument $num is \$$num"
    num=`expr $num + 1`
 done	

この
 eval echo "Argument $num is \$$num"
の部分は eval によって
 echo "Argument 1 is $1"
のように置き換えられこのコマンドが実行されます。
 % bash [このシェルスクリプトファイル] a b c
のようにして試してみてください。
sh, bash スクリプトでは $1 が第一引数、$2 が第二引数を、以下略を意味します。
よって、
 Argument 1 is a
 Argument 2 is b
 Argument 3 is c
のようになるはずです。

一応ついでに説明しておきますと、$# が引数の数で、-le は less or equal (<=) を意味します。
*find との併用 [#m76edcd1]

自分はコマンドラインでは例えば find コマンドを使用してなにか行うときにいきなり exec するとこわいので、まず
 find -exec echo "コマンド ;" \;
のように echo で実験をしてから
 eval `find -exec echo "コマンド ;" \;`
のように実行したりします。` ` で ` ` 内のコマンドの出力を他のコマンドの引数とすることができます。
ミソは
 echo "コマンド ;"
の ; (セミコロン) で、これをつけておかないと、例えば特に意味はないですが
 ls [file1]
 ls [file2]
 ls [file3]
という実行を期待して
 eval `find -exec echo "ls {}" \;`
のようにしてしまうと、
 ls [file1] ls [file2] ls [file3]
となり1つの ls コマンドになってしまいます。
 eval `find -exec echo "ls {}; " \;`
ならば
 ls [file1]; ls [file2]; ls [file3]
のように ; でコマンドが区切られるので期待通りの動作をします。便利な例としては
 % eval `find -exec echo "sed 's/[regexp]/[string]/g' {} > /tmp/tmp; \mv /tmp/tmp {};" \;`
こんなのいかがでしょうか?カレントディレクトリ以下のすべてのファイル中の文字列を置き換えます。

最後にまた、シェル変数を使用しようとすると一度展開されてしまうことを忘れずに。
コマンドラインではそうそうシェル変数を使用しないと思いますが、たまにはまります。

*2段評価 [#u1c40302]

 % eval echo 'ls -d \$HOME'
 ls -d /home/student/1080134
とすれば変数を評価した結果の文字列を得ることができるので、
その後また eval すれば2段評価になりますね。
この例だと2回目に変数がないですが。


#navi(UNIX/コマンド,,footer)
xrea