環境変数を設定するコマンドのプレフィックスとして変数を使用できないのはなぜですか?


11

通常、次のように接頭辞を付けることで、コマンドの環境変数を設定できます。

hello=hi bash -c 'echo $hello'

また、変数を使用して、次のようなコマンド呼び出しの任意の部分を置き換えることができることも知っています。

$ cmd=bash
$ $cmd -c "echo hi" # equivalent to bash -c "echo hi"

環境変数を設定するコマンドの前に変数を使用できないことを知って、私は非常に驚きました。テストケース:

$ prefix=hello=hi
$ echo $prefix # prints hello=hi
$ $prefix bash -c 'echo $hello'
hello=hi: command not found

変数を使用して環境変数を設定できないのはなぜですか?プレフィックス部分は特別な部分ですか?前にevalを使用することで機能させることができましたが、それでも理由がわかりません。bash 4.4を使用しています。


1
env代わりに使用できますeval。IIRCはより安全ですが、遅いです。
wjandrea

回答:


14

私はこれがあなたを捕らえているシーケンスの一部だと思う:

変数の割り当てまたはリダイレクトではない単語は展開されます(シェル展開を参照)。展開後に単語が残っている場合は、最初の単語がコマンドの名前と見なされ、残りの単語が引数になります

これは、Simple Command ExpansionのセクションのBashリファレンスマニュアルからのものです。

このcmd=bash例では、環境変数は設定されておらず、bashはパラメータを展開してコマンドラインを処理し、を残しbash -c "echo hi"ます。

このprefix=hello=hi例では、最初のパスに変数の割り当てはありません。そのため、処理はパラメーターの展開を続行し、最初のワードはになりhello=hiます。

変数の割り当てが処理されると、コマンドの実行中に再処理されません。

以下の処理とその結果を参照してくださいset -x

$ prefix=hello=hi
+ prefix=hello=hi
$ $prefix bash -c 'echo $hello'
+ hello=hi bash -c 'echo $hello'
-bash: hello=hi: command not found
$ hello=42 bash -c 'echo $hello'
+ hello=42
+ bash -c 'echo $hello'
42

「環境変数」としての「変数展開」のより安全なバリエーションについてはeval以下のwjandreaの提案をenv検討してください

prefix=hello=hi
env "$prefix" bash -c 'echo "$hello"'
hi

コマンドにenv環境変数を割り当てるというユーティリティの主な機能を使用しているため、これは厳密にはコマンドライン変数の割り当てではありませんが、同じ目的を達成します。$prefix変数は、名前=値の提供、コマンドラインの処理中に展開されているenvに沿って渡し、bash


3
同様に、$foo=bar bash -c ...$foo=bar変数割り当てではないため(の値は何でも$foo)、変数割り当てのパターンに$foo=bar適合しないため、機能しませんname=value
muru、

3

$prefix割り当てではないからです。@Jeffの方が説明が長い

代わりに関数を使用して同様のことを行うことができます。

$ prefix() { hello=hi "$@"; }
$ prefix bash -c 'echo "$hello"'
hi

...好きなようにそれらを積み重ねることもできます:

$ foo() { foo=123 "$@"; }
$ bar() { bar=456 "$@"; }
$ foo bar bash -c 'echo "$bar $foo"'
456 123
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.