eval
を使用して変数に値を動的に割り当てたい。次のダミーの例は機能します:
var_name="fruit"
var_value="orange"
eval $(echo $var_name=$var_value)
echo $fruit
orange
ただし、変数値にスペースが含まれている場合、$var_value
が二重引用符で囲まれていても、eval
はエラーを返します。
var_name="fruit"
var_value="blue orange"
eval $(echo $var_name="$var_value")
bash: orange : command not found
これを回避する方法はありますか?
Evalを使用しないでください declare
を使用します
$ declare "$var_name=$var_value"
$ echo "fruit: >$fruit<"
fruit: >blue orange<
これにはeval
を使用しないでください。 declare
を使用します。
var_name="fruit"
var_value="blue orange"
declare "$var_name=$var_value"
=
に続くすべてのものがdeclare
によって値として扱われ、最初のWordだけでなく、Word分割が問題にならないことに注意してください。
bash
4.3では、名前付き参照によってこれが少し簡単になりました。
$ declare -n var_name=fruit
$ var_name="blue orange"
$ echo $fruit
blue orange
あなたはcaneval
を機能させますが、それでもいけません:) eval
を使用することは悪い習慣です。
$ eval "$(printf "%q=%q" "$var_name" "$var_value")"
eval
で作業する良い方法は、テストのためにecho
で置き換えることです。 echo
とeval
は同じように機能します(特定の条件下でecho
のようなbash
の実装によって行われる_\x
_拡張を別にしておくと)。
どちらのコマンドも、引数を1つのスペースで結合します。違いは、echo
displays結果であるのに対し、eval
evaluates/interpretsはシェルが結果をコーディングすることです。
だから、どのシェルコードを見るには
_eval $(echo $var_name=$var_value)
_
評価します、あなたは実行することができます:
_$ echo $(echo $var_name=$var_value)
fruit=blue orange
_
それはあなたが望むものではありません、あなたが望むものは:
_fruit=$var_value
_
また、ここで$(echo ...)
を使用しても意味がありません。
上記を出力するには、次を実行します。
_$ echo "$var_name=\$var_value"
fruit=$var_value
_
だから、それを解釈するには、それは簡単です:
_eval "$var_name=\$var_value"
_
個々の配列要素の設定にも使用できることに注意してください。
_var_name='myarray[23]'
var_value='something'
eval "$var_name=\$var_value"
_
他の人が言ったように、コードがbash
固有であることを気にしない場合は、declare
を次のように使用できます。
_declare "$var_name=$var_value"
_
ただし、いくつかの副作用があることに注意してください。
変数のスコープを、それが実行される関数に制限します。たとえば、次のような場合には使用できません。
_setvar() {
var_name=$1 var_value=$2
declare "$var_name=$var_value"
}
setvar foo bar
_
それはfoo
にローカルなsetvar
変数を宣言するため、役に立たないからです。
_bash-4.2
_は、_global変数を宣言するためにdeclare
に_-g
_オプションを追加しましたが、setvar
が設定するので、これは望みのものではありませんa global varこれは、次のように、呼び出し元が関数の場合、呼び出し元の変数ではありません。
_setvar() {
var_name=$1 var_value=$2
declare -g "$var_name=$var_value"
}
foo() {
local myvar
setvar myvar 'some value'
echo "1: $myvar"
}
foo
echo "2: $myvar"
_
出力されます:
_1:
2: some value
_
また、declare
はdeclare
と呼ばれますが(実際にはbash
はKornシェルのtypeset
ビルトインから概念を取り入れました)、変数がすでに設定されている場合、 declare
は新しい変数を宣言せず、割り当ての方法は変数の型によって異なります。
例えば:
_varname=foo
varvalue='([PATH=1000]=something)'
declare "$varname=$varvalue"
_
varname
が以前にscalar、arrayまたはassociative array)として宣言されていた場合、異なる結果が生成されます(また、厄介な副作用が発生する可能性があります。
もし、するなら:
eval "$name=\$val"
...および$name
には;
またはシェルが単純なコマンドを区切ると解釈する可能性のある他のいくつかのトークンが含まれます-適切なシェル構文が前に付いて実行されます。
name='echo hi;varname' val='be careful with eval'
eval "$name=\$val" && echo "$varname"
hi
be careful with eval
ただし、そのようなステートメントの評価と実行を分離することが可能な場合もあります。たとえば、alias
は、コマンドを事前評価するために使用できます。次の例では、変数の定義がalias
に保存されます。これは、評価する$nm
変数に一致しないバイトが含まれていない場合にのみ正常に宣言できますASCII =英数字または_
。
LC_OLD=$LC_ALL LC_ALL=C
alias "${nm##*[!_A-Z0-9a-z]*}=_$nm=\$val" &&
eval "${nm##[0-9]*}" && unalias "$nm"
LC_ALL=$LC_OLD
eval
は、varnameからの新しいalias
の呼び出しを処理するためにここで使用されます。しかし、前のalias
の定義が成功した場合にのみ呼び出されます。多くの異なる実装がalias
の名前にさまざまな種類の値を受け入れることはわかっていますが、まだ完全に空のものを受け入れるものに出くわします。
alias
内の定義は_$nm
用ですが、これは重要な環境値が上書きされないようにするためです。 _
で始まる注目すべき環境値は知らないので、通常はセミプライベート宣言の安全策です。
とにかく、alias
の定義が成功すると、$nm
の値に対応する名前のalias
が宣言されます。また、eval
は、数字でも始まらない場合にのみalias
を呼び出します。それ以外の場合、eval
はnull引数のみを取得します。したがって、両方の条件が満たされた場合、eval
はエイリアスを呼び出し、エイリアスに保存された変数定義が作成されます。その後、新しいalias
がハッシュテーブルから即座に削除されます。