a = $(eval echo hello world)がなぜ間違っていないのですか?

a = $(eval echo hello world)がなぜ間違っていないのですか?

私はこれを偶然見つけました。要約すると、この例は次のようになります。

/ # a=$(eval echo hello world)
/ # echo $a
hello world
/ # $(eval echo hello world)
/bin/sh: hello: not found
/ # a=$(hello world)
/bin/sh: hello: not found

hello world最初の行を括弧内に展開し、最後の行と同じ方法で拡張したいと思いますa=$(hello world)。結局、help evalそれは私たちに次のように言います。

ARGを単一の文字列に結合し、結果をシェルへの入力として使用し、結果コマンドを実行します。

evalがアンローリング前に結果コマンドを実行する場合$()(予想)、結果はhello world実行できないというエラーが発生するはずです(実際のコマンドがない場合hello)。

なぜ a=$(eval echo hello world) 予想通りエラーは発生しませんでした。

答え1

$()が拡張される前にevalが結果コマンドを実行した場合(予想どおり)、結果はエラーになるはずです。なぜなら、hello worldは実行可能ではないからです(実際のhelloコマンドがない限り)。

これは代替案が機能する方法ではありません。単純な存在によって$(..)引き起こされるevalか、または実行されます。


まず、$(..)コマンドの置き換えBashでは、括弧内に実行されたコマンドの出力をキャプチャして変数に保存する方法です。$(..)その中のコンテンツに置き換えられる出力

  1. この部分は、a=$(eval echo hello world)次の順序でシェルによって実行されます。実行はeval echo hello worldechoコマンドを実行し、変数に格納された文字列を出力するのと同じくらい簡単ですecho hello worldhello worlda

  2. 部品は1)の説明に従って返されます$(eval echo hello world)。ただし、どこでも出力をhello worldキャプチャする割り当てはありません。$(..)したがって、リテラル文字列がシェルに返されますhello world。シェルはこれをコマンド(リテラルhello文字列)として解釈しようとします。したがって、その名前のコマンドが見つからないというエラーが表示されます。

  3. 同じことがa=$(hello world)起こります。 1)で述べたように、このセクションでは$(..)括弧内の内容をコマンドとして実行します。したがって、リテラル文字列を再計算すると同じエラーが発生します。

2)と3)の場合、$(..)拡張時に引用符のないリテラル文字列がシェルに返さhello worldれ、トークン化が発生し、hello2worldつの別々の単語として表示されます。これが、hello文字列全体ではなくコマンドとして実行中にエラーが発生する理由ですhello world


evalEvenのように単純なコマンドを使用するときは注意してくださいecho。正しく呼び出されないと、危険なコマンドが実行される危険があります。バラより常に使用しても安全ですかeval echo

関連情報