web-dev-qa-db-ja.com

eval対bashのパイプ

使用の違いは何ですか:

eval 'echo "foo"'

そして

echo 'echo "foo"' | bash

何かありますか?

6
Alexander Mills

短い答え

evalによって実行されるコマンドは現在のシェルで実行され、bashにパイプされたコマンドはサブシェルで実行されます。例:

> echo 'x=42' | bash; echo $x

> eval 'x=42'; echo $x
42

より長い答え

コメントで、bash(> = 4.2)のより新しいバージョンでは、最初のコマンドも同じ効果を持つ可能性があると主張されました。しかし、これはそうではないようです。

実際には、パイプされたコマンドが現在のセッションで実行されない原因となるいくつかの要因があります。パイプとbashコマンドです。

ほとんどの場合、パイプされたコマンドはサブシェルで実行されます。 Bashマニュアル( セクション3.2.2:パイプライン )には、次のように書かれています。

パイプライン内の各コマンドは、独自のサブシェルで実行されます( コマンド実行環境 を参照)。

コメントで指摘されているように、この動作はlastpipeオプションを使用して変更できます。 Bashマニュアル( セクション4.3.2:Shoptビルトイン )は、lastpipeオプションについて次のように述べています。

ラストパイプ

設定され、ジョブ制御がアクティブでない場合、シェルは現在のシェル環境でバックグラウンドで実行されていないパイプラインの最後のコマンドを実行します。

これは、次のようにして確認できます。

最初にlastpipeを有効にします。

> shopt -s lastpipe

次に、ジョブ制御を無効にします。

> set +m

次に、パイプ内から変数を設定するコマンドを実行します。

> unset x
> echo x=42 | while IFS= read -r line; do eval "${line}"; done;
> echo $x
42

whileコマンドはstdinから入力を読み取ることができないため、readループとevalコマンドを回避策として使用していることに注意してください(したがって、パイプから入力を取得できません)。 。

この例は、パイプの右端のコマンドが実際には現在のシェルで実行できることを示しています。ただし、これは実際には元の例には影響しません。 lastpipeを有効にし、ジョブ制御を無効にしても、bashにパイプすると、次の結果が得られます。

> echo 'x=42' | bash; echo $x

>

これは、bashコマンド自体がサブシェルで入力を実行するためです。

20
igal