web-dev-qa-db-ja.com

変数に保存されたコマンドを実行する方法は?

変数に保存されているコマンドを呼び出す正しい方法は何ですか?
1と2に違いはありますか?

#!/bin/sh
cmd="ls -la $APPROOTDIR | grep exception"
#1
$cmd
#2
eval "$cmd"
77

Unixシェルは、入力の各行で一連の変換を実行してから実行します。ほとんどのシェルでは、次のようになります(bashのマンページから引用):

  • 初期の単語分割
  • ブレースの拡張
  • チルダ展開
  • パラメータ、変数および算術展開
  • コマンド置換
  • 二次語分割
  • パス展開(別名グロビング)
  • 引用符の削除

$cmdを直接使用すると、パラメーター展開フェーズでコマンドに置き換えられ、その後、すべての次の変換が行われます。

eval "$cmd"を使用しても、$cmdがそのまま返され、パラメーターとしてevalにパラメーターとして渡される引用削除フェーズまで何も実行されません。

したがって、基本的にはほとんどの場合同じであり、コマンドがパラメーター展開までの変換ステップを使用する場合は異なります。たとえば、ブレース展開を使用する場合:

$ cmd="echo foo{bar,baz}"
$ $cmd
foo{bar,baz}
$ eval "$cmd"
foobar foobaz
88
JB.

eval $cmdを行うときに(インタラクティブに、およびスクリプトで)cmd="ls -l"を行うだけで、目的の結果が得られます。あなたの場合、パターンのないgrepを持つパイプがあるため、grep部分はエラーメッセージで失敗します。ただ$cmdは、「コマンドが見つかりません」(またはそのような)メッセージを生成します。したがって、evalを使用して、エラーメッセージを生成するコマンドではなく、完成したコマンドを使用してみてください。

5
Henno Brandsma

$cmdは、変数をその値で置き換え、コマンドラインで実行するだけです。 eval "$cmd"は、コマンドラインで結果の値を実行する前に変数の展開とコマンドの置換を行います

2番目の方法は、柔軟性のないコマンドを実行する場合などに役立ちます。
for i in {$a..$b}
フォーマットループは変数を許可しないため機能しません。
この場合、bashまたはevalへのパイプが回避策です。

Mac OSX 10.6.8、Bash 3.2.48でテスト済み

0
Zimba