rm /blog

IT系技術職のおっさんがIT技術とかライブとか日常とか雑多に語るブログです。* 本ブログに書かれている内容は個人の意見・感想であり、特定の組織に属するものではありません。/All opinions are my own.*

【UNIX】evalコマンドについて

動的にコマンド文字列を作って実行したい場合、そのまま文字列を書いて「`」で評価すると、
コマンド文字列内になる「'」がえてして邪魔になるときがある。
これを回避するために個人的にはよくevalを使う。

例えば以下のようなケースではうまい具合にコマンドが実行されない↓

for i in `seq 0 31`;do
	cmd_wk="date +%Y/%m/%d --'""$i days ago""'";
	echo "`$cmd_wk`"; ←ここがうまくいかない
done

これは
”現在日付から1日ずつさかのぼって日付をYYYY/MM/DD形式で標準出力する”
ことを実現したいのだが、実行すると

date: 認識できないオプション`--'0'です
詳しくは `date --help' を実行して下さい.

といわれて実行に失敗する。

これを回避するためにevalを使って

for i in `seq 0 31`;do
	cmd_wk="date +%Y/%m/%d --'""$i days ago""'";
	eval $cmd_wk
done

とするとうまくいく。

2014/10/06
2014/10/05
…
2014/09/06
2014/09/05

↑2014/10/6に実行したのでこんな感じの標準出力になる。
実際には32行出力される。


evalは引数に「実行したいコマンド文字列」を渡す。
そういう意味ではxargsに近いかもしれない(テクニックやコマンド原理の相似点はよく知らない)
最も単純な使い方では「eval ls」のようなものが出来るが、これは要するに「ls」と同じである。
「eval ls -las」なら「ls -las」と同じ効果を得る。

このevalは引数に渡した文字列そのものをコマンドとして実行しようとするので、
例えば「eval `date +%Y/%m/%d' '%H:%M:%S`」のようなevalコマンドは通常失敗する。
⇒これは引数部分の`date +%Y/%m/%d' '%H:%M:%S`="2014/10/06 10:21:44"という文字列をコマンドとみなすので
 自分の環境変数に指定された「2014/10/06」というコマンドを実行しようとするが、
 そんなコマンドはない旨のエラーが表示されることを表している。


 

 
余談だが、eval内ではコマンドのエイリアス回避を意味する先頭部の「\」(半角円マーク)の効果が得られないようだ。
例えばlsについて、「which ls」の結果が以下のようであった場合、

alias ls='ls --color=tty'
        /bin/ls

↑のエイリアス設定に従えば、単に「ls」だけ打ったとしても結果に色がついてくれる。
一般的にこれを回避する意味で先頭に「\」をいれる⇒「\ls(=/bin/ls)」と「 --color=tty」のオプション部分がなくなるので、結果に色は付かない。
ただし、同じ目的で「eval \ls」と実行しても、結果に色が付く。エイリアスが生きる。
もしeval経由で呼び出すコマンドのエイリアスを無視するなら、(今回のケースでいえば)先頭に半角円マークを付けるのではなく
本来のコマンド位置/bin/lsを直接指定してやるしか方法はない。
まとめると(lsのエイリアス設定は上記に即す)

 

コマンドエイリアス有効?

ls 有効
\ls 無効(エイリアスを無視する)
/bin/ls 無効(エイリアスを無視する)
eval ls 有効
eval \ls 有効(エイリアスは無視されない)
eval /bin/ls 無効(エイリアスを無視する)

となるようである。