web-dev-qa-db-ja.com

コマンドラインで環境変数を設定してコマンドに表示するにはどうすればよいですか?

走れば

export TEST=foo
echo $TEST

Fooを出力します。

走れば

TEST=foo echo $TEST

ありません。エクスポートやスクリプトを使用せずにこの機能を取得するにはどうすればよいですか?

175
ashleysmithgpu

これは、シェルがコマンドラインで変数を展開するためですbeforeそれは実際にコマンドを実行し、その時点では変数は存在しません。使用する場合

TEST=foo; echo $TEST

それが動作します。

exportは、その後に実行されるコマンドの環境に変数を表示します(これがbashでどのように機能するかについては、help exportを参照してください)。変数が1つのコマンドの環境に表示されるだけでよい場合は、試したものを使用してください。

TEST=foo your-application
209
peterph

環境変数ではなくShell変数でスコープを制限したいのではないでしょうか。環境変数は、コマンドが実行されるのときにコマンドに渡される文字列のリストです。

var=value echo whatever

エコーが受信する環境にvar=value文字列を渡しています。ただし、echoは環境リストに対して何の処理も行いません¹。ほとんどのシェルではとにかく、echoが組み込まれているため、実行されません

あなたが書いていたなら

var=value sh -c 'echo "$var"'

それは別の問題だったでしょう。ここでは、var=valueshコマンドに渡していますが、shはたまたまその環境を使用しています。シェルは、環境から受け取る各変数をシェル変数に変換するため、var環境変数shが受け取る$var変数に変換され、そのechoコマンドラインで展開すると、echo valueになります。環境はデフォルトで継承されるため、echoはその環境でvar=valueも受け取ります(または、実行された場合は受け取ります)。ただし、echoは環境を考慮しません。

さて、私が疑っているように、シェル変数のスコープを制限したいのであれば、いくつかの可能なアプローチがあります。

移植可能(BourneおよびPOSIX):

(var=value; echo "1: $var"); echo "2: $var"

上記の(...)はサブシェル(ほとんどのシェルでは新しいシェルプロセス)を開始するので、そこで宣言された変数はそのサブシェルにのみ影響するので、上記のコードは「1:値」を出力するはずです。および「2:」または「2:whatever-var-was-set-to-before」。

ほとんどのBourneのようなシェルでは、関数と「ローカル」ビルトインを使用できます。

f() {
  local var
  var=value
  echo "1: $var"
}
f
echo "2: $var"

Zshでは、インライン関数を使用できます。

(){ local var=value; echo "1: $var"; }; echo "2: $var"

または:

function { local var=value; echo "1: $var"; }; echo "2: $var"

Bashとzsh(ash、pdksh、AT&T kshは除く)では、このトリックも機能します。

var=value eval 'echo "1: $var"'; echo "2: $var"

いくつかのシェル(dashmkshyash)では機能するが、zshでは機能しないバリアント(sh/kshエミュレーションを除く):

var=value command eval 'echo "1: $var"'; echo "2: $var"

(POSIXシェルで特殊な組み込み関数(ここではcommand)の前にevalを使用すると、特殊性が取り除かれます(これらの変数の代入は、それらが戻った後も有効のままです)。


¹厳密に言えば、それは完全に真実ではありません。いくつかの実装では、ローカリゼーション環境変数(LANGLOCPATHLC_*...)、GNU実装では、POSIXLY_CORRECT環境変数を考慮します(env echo --versionPOSIXLY_CORRECT=1 env echo --versionを比較するGNUシステム)。

43

あなたはそれを正しくやっていますが、bash構文は誤解しやすいです:echo $TESTは、echoTEST env varをフェッチしてから出力させますが、そうしません。だから与えられた

export TEST=123

その後

TEST=456 echo $TEST

次のシーケンスが含まれます。

  1. シェルはコマンドライン全体を解析し、すべての変数置換を実行するため、コマンドラインは次のようになります。

    TEST=456 echo 123
    
  2. コマンドの前に一時変数セットを作成するため、TESTの現在の値を保存し、456で上書きします。コマンドラインは今です

    echo 123
    
  3. 残りのコマンドを実行します。この場合、123がstdoutに出力されます(そのため、残っているシェルコマンドはTESTのtemp値も使用していません)。

  4. TESTの値を復元します

変数の置換を含まないため、代わりにprintenvを使用してください。

>> export TEST=123
>> printenv TEST
123
>> TEST=456 printenv TEST
456
>> printenv TEST && TEST=456 printenv TEST && TEST=789 printenv TEST && printenv TEST
123
456
789
123
>>
10
Oliver

あなたはこれを使ってこれを機能させることができます:

TEST=foo && echo $TEST
5
pradeepchhetri