web-dev-qa-db-ja.com

「A = 10 echo $ A」が10を印刷しないのはなぜですか?

このコマンド:

A=10 echo $A

空の行を出力します。なぜ10ではありませんか?インプレースの一時的な環境設定が機能しないのはなぜですか?

解決策よりも理由と説明を知りたい。

私は使った

LANG=C gcc ...

gccにシステム言語(中国語)の代わりにフォールバック言語(英語)を使用するように強制します。したがって、VAR=valueプレフィックスがそれに続くコマンドの一時的な環境をセットアップすると想定しています。しかし、私にはいくつかの誤解があるようです。

25
Earth Engine

コマンドを評価するさまざまなステップが発生する順序の問題です。

A=10 echo $Aは、最初にコマンドを3つの単語A=10echo、および$Aで構成される単純なコマンドに解析します。次に、各Wordで変数の置換、つまり$Aなどの変数展開の値への変換が行われます(目に見えるものを何もしないステップは省略しています)。

Aの値が最初にfooである場合、展開ステップの結果は、A=10echo、およびfooの3つの単語を含む単純なコマンドになります。 (シェルはこの時点で、どの文字が最初に引用符で囲まれていたかを記憶します。この場合はどれもありません。)次のステップはコマンドの実行です。 A=10は有効な変数名で始まり、その後に等号が続くため、割り当てとして扱われます。変数のAは、コマンドの実行中にシェルと環境の両方で10に設定されます。 (通常、シェル変数としてだけでなく、環境内にAを持つexport Aを記述する必要があります。これは例外です。次のWordは割り当てではないため、コマンド名として扱われます。 (これは組み込みコマンドです)。 echoコマンドは変数に依存しないため、A=10 echo $Aecho $Aとまったく同じ効果があります。

コマンドの実行中のみ変数を設定したいが、コマンドの実行中に割り当てを考慮する場合は、サブシェルを使用できます。括弧で示されたサブシェルは、すべての状態の変更(変数の割り当て、現在のディレクトリ、関数定義など)をサブシェルに対してローカルにします。

(A=10; echo $A)

変数を環境にエクスポートして、外部プログラムから見えるようにする場合は、export A=10を作成します。

22
Gilles

LANG=C gcc ...を使用すると、シェルがgccの環境にLANGを設定しますonly、およびnotcurrent環境自体に設定されます( 注を参照)。したがって、gccfinishesの後、LANGは以前の値に戻ります(または設定解除されます)。

さらに、A=10 echo $Aを使用すると、エコーではなく$ Aを置換するShellになり、この置換(「拡張」と呼ばれる)が発生しますbeforeステートメントは評価(割り当てを含む)であるため、期待どおりに機能するためには、Aの値が、そのステートメントの前にcurrent環境で既に設定されている必要があります。

A=10 echo $Aが期待どおりに機能しないのはそのためです。A=10はエコーに対して設定されますが、エコーは内部的に環境変数Aの値を無視します。 $Aは、現在のシェル(なし)で設定された値に置き換えられ、thenはechoの引数として渡されます。

したがって、あなたの仮定は正しいです:VAR=value commanddoes work、しかしこれは内部的にcommandses VARの場合にのみ関連します。そうでない場合でも、valueargumentとしてcommandに渡すことができますが、引数はcurrentシェルに置き換えられるため、使用前に設定する必要があります:VAR=value; command "$VAR"

実行可能スクリプトの作成方法がわかっている場合は、テストとしてこれを試すことができます。

#!/bin/sh
echo "1st argument is $1"
echo "A is $A"

testscriptとして保存して、試してください:

$ A=5; A=10 testscript "$A"; echo "$A"
1st argument is 5
A is 10
5

最後になりましたが、Shellenvironment変数とプログラムargumentsの違いを知っておく価値があります。

以下に参考資料を示します。

(*)注:技術的にはシェルdoes現在の環境でも設定されます。その理由は次のとおりです。echoreadtestなどの一部のコマンドはShell builtinsです。子プロセスを生成しないでください。現在の環境で実行されます。ただし、シェルは、コマンドが実行されるまで割り当てが継続するだけなので、実際の目的ではすべて同じ効果があります。割り当てはその単一のコマンドによってのみ表示されます。

37
MestreLion

あなたが明らかに望んでいることをする1つのおそらくきれいな方法は、コマンドを発行することです:

A=10 eval 'echo $A'

実際には、値10の置換を$ Aの場所に後のコンテキスト(つまり、割り当てについて既に知っているevalの「内部」)に延期します。単一引用符は必須です。このような構造は、現在の環境を汚染するリスクを冒すことなく、割り当てを目的のコマンド(この場合はエコー)に明確に伝えます。

3
nhokka