同僚の1人が、慣れていないBash構文を提供してくれました。私のGoogle fooは、それが何をするのか、なぜ/いつそれを使用する必要があるのかを理解するのに失敗しました。
彼が私に送ったコマンドは次の形式でした:
someVariable=something command
最初は、これは以下と同等であると思いました。
someVariable=something ; command
または
someVariable=something
command
しかし、これはケースに表示されません。例:
[Jan-03 11:26][~]$ # Look at the environment variable BAZ. It is currently empty
[Jan-03 11:26][~]$ echo $BAZ
[Jan-03 11:27][~]$ # Try running a command of the same format
[Jan-03 11:27][~]$ BAZ=jake echo $BAZ
[Jan-03 11:27][~]$
[Jan-03 11:27][~]$ # Now, echo BAZ again. It is still empty:
[Jan-03 11:27][~]$ echo $BAZ
[Jan-03 11:27][~]$
[Jan-03 11:28][~]$
[Jan-03 11:28][~]$ # If we add a semi-colon to the command, we get dramatically different results:
[Jan-03 11:28][~]$ BAZ=jake ; echo $BAZ
jake
[Jan-03 11:28][~]$
[Jan-03 11:28][~]$ # And we can see that the variable is actually set:
[Jan-03 11:29][~]$ echo $BAZ
jake
[Jan-03 11:29][~]$
この構文は何をしますか?設定された変数はどうなりますか?なぜこれが機能するのですか?
これは次と同等です。
( export someVariable=something; command )
これにより、someVariable
は、割り当てられた値を持つ環境変数になりますが、実行されるコマンドに対してのみです。
bash
マニュアルの関連部分は次のとおりです。
シンプルなコマンド
単純なコマンドは、一連のオプションの変数割り当ての後に空白で区切られた単語とリダイレクトが続き、制御演算子で終了します。最初のWordは実行されるコマンドを指定し、引数ゼロとして渡されます。残りの単語は、呼び出されたコマンドの引数として渡されます。
(...)
シンプルなコマンド拡張
[コマンド展開から]コマンド名が得られない場合、変数の割り当ては現在のシェル環境に影響します。それ以外の場合、変数は実行されたコマンドの環境に追加され、現在のシェル環境に影響を与えません。
注:これはbash
に固有のものではなく、 POSIXで指定 であることに注意してください。
編集-回答のコメントから要約されたディスカッション
理由 BAZ=JAKE echo $BAZ
、JAKEを出力しないのは、変数置換が何よりも先に行われるためです。変数置換をバイパスすると、これは期待どおりに動作します。
$ echo_baz() { echo "[$BAZ]"; }
$ BAZ=Jake echo_baz
[Jake]
$ echo_baz
[]
これらは シンプルコマンド のコンテキストでの変数割り当てです。 xhienne で述べたように、外部コマンドの場合、コマンドの実行中に割り当てられた値をエクスポートすることと同じです。
例では組み込みコマンドを使用しているため、動作はまったく異なります。割り当ては現在の環境に影響しますが、組み込みコマンドの実行後に効果が持続するかどうかは指定されていません。例を理解するには、変数が処理される前にパラメーターの展開が行われることを知っておく必要があります。したがって
BAZ=jake echo $BAZ
シェルは最初に$BAZ
を展開し(結果は何もない)、次にBAZ
をjake
に設定し、最後に実行します
echo
空の行を出力します。 (その後、シェルは、後続のecho $BAZ
が示すようにBAZ
を忘れます。)
BAZ=jake; echo $BAZ
は2つのコマンドとして解釈されます。最初にBAZ
変数が現在の環境で設定され、次にecho $BAZ
がecho jake
に展開されて実行されます。
ここで発生する重要なことがいくつかあります。
bashリファレンスマニュアル 、簡単なコマンド拡張、セクション「コマンド名が生成されない場合、変数の割り当ては現在のシェル環境に影響します。それ以外の場合は、変数が追加されます。実行されたコマンドの環境に、現在のシェル環境には影響しません。」したがって、var="something" command arg1 arg2
と言うと、コマンドはvar
がコマンドの環境にあり、command
が終了すると消えて実行されます。これのデモは簡単です。コマンド内からコマンドの環境にアクセスします。
$ BAZ="jake" python -c "import os; print os.environ['BAZ']"
jake
これは驚くべきことではありません。このような構文は、環境が変更されたプログラムを実行するために頻繁に使用されます。私の仲間のunix.stackexchange.comとaskubuntu.comのユーザーは、この例を認識します。ユーザーがドイツ語のロケールを使用していて、英語のみで話す場合は、発生している問題を再現し、次のように英語で出力を取得するように依頼できます。
LC_ALL=C command
また、環境アクセスはpython
に固有のものではないことにも注意してください。 C
またはその他のプログラミング言語を使用して実行できます。それはたまたまたまたま私の「選択した武器」であり、このデモでのみ使用されました。
変数の展開は、何かが実行される前に行われます。したがって、BAZ="foo" echo $BAZ
のようなものを実行すると、シェルは最初にその環境を調べ、そこで変数BAZを検出しないため、$BAZ
を空のままにします。その簡単なデモンストレーションは次のとおりです。
$ BAZ="jake" python -c "import sys; print 'ARG:',sys.argv[1]" $BAZ
ARG:
Traceback (most recent call last):
File "<string>", line 1, in <module>
IndexError: list index out of range
また、2つの別個のコマンドステートメントであるBAZ=jake; echo $BAZ
との違いも重要です。ここで、BAZ=jake
はシェルの環境に残ります。ユースケースはあなたの意図に依存します。そのような変数を必要とする複数のプログラムを実行する場合は、そのような変数をexport
することが望ましい場合があります。この1つの特定の時間だけ必要な場合は、先行する変数の割り当てが望ましい場合があります。
簡単な言葉で:
BAZ=jake echo $BAZ
variable substitution
はコマンドの最初に行われるため、何も出力されません。つまり、このコマンドラインで最初に発生するのは$BAZ
で、変数BAZ
が定義されている実際の値(存在する場合)に置き換えられます。これは、シェルが同じコマンドラインでBAZ=jake
を考慮する前でも起こります。
コマンドの実行前は、BAZ
には値が割り当てられておらず、BAZ=jake
は$BAZ
が解決された後にのみ考慮されるため、$BAZ
は解決されません任意の値。したがって、echo $BAZ
は何も出力しません。
BAZ=jake
は指定されたコマンドの一部にすぎません(シェルはそれを環境変数と見なしたり設定したりしません)。これは、同じコマンドラインの一部として実行されるプロセスがこの変数BAZ
を使用する場合に、ほとんど役に立ちます。コマンドの実行が完了すると、BAZ
、jake
の値は揮発性になります。
例:]# LD_LIBRARY_PATH="new_path" ldconfig
、ここでldconfig
コマンドは内部的に変数LD_LIBRARY_PATH
を参照し、このコマンドラインには変数の展開はありません上記とは異なり。
その他の場合:
BAZ=jake; echo $BAZ
これらは、1行で示される2つの異なるコマンドです。次々と実行するのと同じくらい良いです。