web-dev-qa-db-ja.com

条件式の「set -e」での「eval」の動作

コマンドを検討する

eval false || echo ok
echo also ok

通常、これはfalseユーティリティを実行し、終了ステータスがゼロ以外であるため、echo okおよびecho also okを実行することを期待します。

私が使用するすべてのPOSIX風のシェルで(ksh93zshbashdash、OpenBSD ksh、およびyash)、これは何が起こるかですが、set -eを有効にすると興味深いことが起こります。

set -eが有効な場合、OpenBSDのshおよびkshシェル(どちらもpdkshから派生)は、evalの実行時にスクリプトを終了します。他のシェルはそれを行いません。

POSIXによると 特殊な組み込みユーティリティ(evalなど)のエラーにより、非インタラクティブシェルが終了するはずです。 falseの実行が「エラー」を構成するかどうかは完全にはわかりません(もしそうであれば、それはset -eがアクティブであることとは無関係です)。

これを回避する方法は、evalをサブシェルに置くことです。

( eval false ) || echo ok
echo also ok

問題は、POSIXに準拠した正しいシェルスクリプトでそれを実行する必要があるかどうか、またはそれがOpenBSDのシェルのバグかどうかです。また、上記にリンクされているPOSIXテキストの「エラー」とはどういう意味ですか?


情報の追加:OpenBSDシェルは、コマンドでecho okの有無にかかわらずset -eを実行します

eval ! true || echo ok

私の元のコードは次のようになりました

set -e
if eval "$string"; then
    echo ok
else
    echo not ok
fi

openBSDシェルを使用してnotnot okstring=falseで出力します(終了します)。意図的に、誤って、または誤解して、あるいは何か他のものでした。

9
Kusalananda

他のシェルがそのような回避策を必要としないことは、それがOpenBSD kshのバグであることを強く示しています。実際、ksh93はそのような問題を示していません。

コマンドラインに||があることは、その左側の戻りコード1によって引き起こされるシェル出口を回避する必要があることを意味します。

specialビルトインのエラーにより、非対話型シェル POSIXに従って が終了しますが、常にそうであるとは限りません。ループからcontinueを実行しようとするとエラーが発生し、continueは組み込みです。しかし、ほとんどのシェルは終了しません:

continue 3

明確なエラーを発生するが終了しない組み込み関数。

したがって、falseの出口は、コマンドの組み込み特性(この場合はeval)ではなく、set -e条件によって生成されます。

set -eが終了する正確な条件は、POSIXではかなりあいまいです。

4
Isaac

[これが本当の答えではない場合は申し訳ありませんが、問題が出てきたら更新します]

私はソースコードを見て、私の結論は次のとおりです。

1)それはバグ/制限であり、その背後に哲学的なものは何もありません。

2)OpenBSDのksh(mksh)のポータブルフォークからの「修正」はvery貧弱で、実際に修正せずに事態を悪化させるだけです。

他のすべてのシェルとは異なる新しいバグ:

mksh -ec 'eval "false; echo yup"'
yup

bash -ec 'eval "false; echo yup"'
(nothing)

まだ本当に修正されていません:

mksh -ec 'eval "set -e; false" || echo yup'
(nothing)

bash -ec 'eval "set -e; false" || echo yup'
yup

上記のbashdashzshyashksh93などに置き換えることができます。

4
mosvy