変数に保存されているコマンドを呼び出す正しい方法は何ですか?
1と2に違いはありますか?
#!/bin/sh
cmd="ls -la $APPROOTDIR | grep exception"
#1
$cmd
#2
eval "$cmd"
Unixシェルは、入力の各行で一連の変換を実行してから実行します。ほとんどのシェルでは、次のようになります(bash
のマンページから引用):
$cmd
を直接使用すると、パラメーター展開フェーズでコマンドに置き換えられ、その後、すべての次の変換が行われます。
eval "$cmd"
を使用しても、$cmd
がそのまま返され、パラメーターとしてeval
にパラメーターとして渡される引用削除フェーズまで何も実行されません。
したがって、基本的にはほとんどの場合同じであり、コマンドがパラメーター展開までの変換ステップを使用する場合は異なります。たとえば、ブレース展開を使用する場合:
$ cmd="echo foo{bar,baz}"
$ $cmd
foo{bar,baz}
$ eval "$cmd"
foobar foobaz
eval $cmd
を行うときに(インタラクティブに、およびスクリプトで)cmd="ls -l"
を行うだけで、目的の結果が得られます。あなたの場合、パターンのないgrepを持つパイプがあるため、grep部分はエラーメッセージで失敗します。ただ$cmd
は、「コマンドが見つかりません」(またはそのような)メッセージを生成します。したがって、evalを使用して、エラーメッセージを生成するコマンドではなく、完成したコマンドを使用してみてください。
$cmd
は、変数をその値で置き換え、コマンドラインで実行するだけです。 eval "$cmd"
は、コマンドラインで結果の値を実行する前に変数の展開とコマンドの置換を行います
2番目の方法は、柔軟性のないコマンドを実行する場合などに役立ちます。for i in {$a..$b}
フォーマットループは変数を許可しないため機能しません。
この場合、bashまたはevalへのパイプが回避策です。
Mac OSX 10.6.8、Bash 3.2.48でテスト済み