このスニペットを検討してください。
$ SOMEVAR=AAA
$ echo zzz $SOMEVAR zzz
zzz AAA zzz
ここで、最初の行で$SOMEVAR
をAAA
に設定しました。2行目でエコーすると、AAA
の内容が期待どおりに取得されます。
しかし、その後、echo
と同じコマンドラインで変数を指定しようとすると:
$ SOMEVAR=BBB echo zzz $SOMEVAR zzz
zzz AAA zzz
...期待どおりBBB
を取得できません-古い値(AAA
)を取得します。
これは物事がどうあるべきか?もしそうなら、どうしてLD_PRELOAD=/... program args ...
のような変数を指定して動作させることができますか?私は何が欠けていますか?
予想される動作が表示されます。問題は、変更された環境でコマンドを呼び出す前に、親シェルがコマンドラインで$SOMEVAR
を評価することです。環境が設定されるまで、$SOMEVAR
の評価を延期する必要があります。
直接のオプションは次のとおりです。
SOMEVAR=BBB eval echo zzz '$SOMEVAR' zzz
。SOMEVAR=BBB sh -c 'echo zzz $SOMEVAR zzz'
。どちらも単一引用符を使用して、親シェルが$SOMEVAR
を評価しないようにします。環境で設定された後にのみ(一時的に、単一コマンドの実行中に)評価されます。
別のオプションは、サブシェル表記を使用することです( answer の Marcus Kuhn によっても示唆されています):
(SOMEVAR=BBB; echo zzz $SOMEVAR zzz)
変数はサブシェルでのみ設定されます
率直に言って、マニュアルはこの点で混乱しています。 GNU Bashマニュアル のコメント:
単純なコマンドまたは関数の環境[ビルトインを除くことに注意]は、シェルパラメータで説明されているように、パラメータの割り当てをプレフィックスとして付けることで一時的に拡張できます。これらの割り当てステートメントは、そのコマンドから見える環境にのみ影響します。
本当に文を解析する場合、コマンド/関数のenvironmentは変更されますが、親プロセスの環境は変更されません。したがって、これは動作します:
$ TESTVAR=bbb env | fgrep TESTVAR
TESTVAR=bbb
envコマンドの環境は実行前に変更されているためです。ただし、これは機能しません。
$ set -x; TESTVAR=bbb echo aaa $TESTVAR ccc
+ TESTVAR=bbb
+ echo aaa ccc
aaa ccc
シェルによってパラメーターの展開が実行されるためです。
問題の別の部分は、Bash これらのステップを定義する そのインタープリターのためです:
ここで起こっているのは、ビルトインが独自の実行環境を取得していないため、変更された環境が表示されないことです。さらに、単純なコマンド(例:/ bin/echo)doは変更された環境を取得します(これがenvの例が機能した理由です)が、シェルの展開は手順4でcurrent環境に配置します。
つまり、「aaa $ TESTVAR ccc」を/ bin/echoに渡していないということです。補間された文字列(現在の環境で展開される)を/ bin/echoに渡します。この場合、現在の環境には[〜#〜] testvar [〜#〜]がないため、単に 'aaa ccc'をコマンド。
ドキュメントは、はるかに明確になる可能性があります。スタックオーバーフローがあるのは良いことです。
http://www.gnu.org/software/bash/manual/bashref.html#Command-Execution-Environment
目的を達成するには、使用します
( SOMEVAR=BBB; echo zzz $SOMEVAR zzz )
理由:
次のコマンドから割り当てをセミコロンまたは改行で区切る必要があります。そうしないと、次のコマンド(エコー)でパラメータ展開が発生する前に割り当てが実行されません。
subshell環境内で割り当てを行う必要があります。これは、現在の行を超えて保持されないようにするためです。
このソリューションは、他のいくつかが提案したものよりも短く、簡潔で効率的であり、特に新しいプロセスを作成しません。
これは、これにより1行の環境変数が設定されるためです。ただし、echo
は展開を行いませんが、bash
は展開します。したがって、echoコマンドのコンテキストではSOME_VAR
がBBB
であっても、実際にはコマンドが実行される前に変数が展開されます。
効果を確認するには、次のようなことができます。
$ SOME_VAR=BBB bash -c 'echo $SOME_VAR'
BBB
ここでは、子プロセスが実行されるまで変数は展開されないため、更新された値が表示されます。親シェルでSOME_VARIABLE
を再度チェックすると、期待どおりAAA
のままです。
代替案は次のとおりです。
SOMEVAR=BBB && echo zzz $SOMEVAR zzz
SOMEVAR=BBB; echo zzz $SOMEVAR zzz
使う ;同じ行にあるステートメントを分離します。