私はこれを偶然見つけました。要約すると、この例は次のようになります。
/ # 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では、括弧内に実行されたコマンドの出力をキャプチャして変数に保存する方法です。$(..)
その中のコンテンツに置き換えられる出力
この部分は、
a=$(eval echo hello world)
次の順序でシェルによって実行されます。実行はeval echo hello world
echoコマンドを実行し、変数に格納された文字列を出力するのと同じくらい簡単ですecho hello world
。hello world
a
部品は1)の説明に従って返されます
$(eval echo hello world)
。ただし、どこでも出力をhello world
キャプチャする割り当てはありません。$(..)
したがって、リテラル文字列がシェルに返されますhello world
。シェルはこれをコマンド(リテラルhello
文字列)として解釈しようとします。したがって、その名前のコマンドが見つからないというエラーが表示されます。同じことが
a=$(hello world)
起こります。 1)で述べたように、このセクションでは$(..)
括弧内の内容をコマンドとして実行します。したがって、リテラル文字列を再計算すると同じエラーが発生します。
2)と3)の場合、$(..)
拡張時に引用符のないリテラル文字列がシェルに返さhello world
れ、トークン化が発生し、hello
2world
つの別々の単語として表示されます。これが、hello
文字列全体ではなくコマンドとして実行中にエラーが発生する理由ですhello world
。
eval
Evenのように単純なコマンドを使用するときは注意してくださいecho
。正しく呼び出されないと、危険なコマンドが実行される危険があります。バラより常に使用しても安全ですかeval echo
?