シェル論理否定

シェル論理否定

どちらに何が好きですか?

if ! [ ... ]; then

そして

if [ ! ... ]; then

実際、結果は同じです。好みの構文はありますか?前者の構文ではnotがシェル組み込みと評価され、後者の構文ではnotが組み込みと評価されますtest

答え1

移植性に関する考慮事項

キーワードはPOSIXですが、Bourneではなく/コマンドは!最初から!サポートされています。[test

だから[ ! ... ]! [ ... ]

-oそれ以外の場合は、廃止された演算子と二項演算子を使用しない限り、同じでなければなりません(実装時に古い/解析バグを除外する-a場合)。test[

実際、Bourneシェルは次のことを行います。

if ! cmd1; then
  cmd2
fi

あなたはこれをしなければなりません:

if cmd1; then
  :
else
  cmd2
fi

(またはを使用してくださいcmd1 || cmd2。しかし、最終的にシャットダウン状態が変わる可能性があります)。

set -o errexit//set -eトラップとの対話ERR

iffi@mosvyが指摘したように、/ステートメントの条件付き部分に加えて、間[ ! ... ]のもう1つの違いは、後者が! [ ... ]falseを返し、オプションがオンになってもシェルが終了しないことです。! [ ... ]errexit

!errexitパイプに適用すると、シェルはパイプの終了状態を次のように見なすため、効果はキャンセルされます。状況failing-pipeline || cmdにも同様に適用されるかfailing-pipeline && cmd...

そしてそれは[ ! ... ]コマンド!に渡される一般的なパラメータです[。最終的にシェルに関する限り、これは成功または失敗の終了状態を返すコマンドerrexitです。[

$ sh -ec '[ ! a = a ]; echo here'; echo "$?"
1
$ sh -ec '! [ a = a ]; echo here'; echo "$?"
here
0

ifこれは、に示されているように、while//ステートメントの条件付き部分としてこれらのコマンドが実行される場合には適用されません。untilerrexit

ERRKornの砲弾のような落とし穴にも同じことが当てはまります。

$ ksh -c 'trap "echo OUCH" ERR; ! [ a = a ]'
$ ksh -c 'trap "echo OUCH" ERR; [ ! a = a ]'
OUCH

実際、これは[ほとんど常に条件として使用され、適用されない場合( //ステートメントまたは後に/が続く場合)には適用されないerrexitため、おそらく違いはありません。ifwhileuntil&&||

答え2

[ … ]同じtest …、だから! [ … ]同じ! test …。これはコマンドの結果を否定することを意味しますtest。この場合は!シェルコマンドです。

info bashたとえば、「パイプライン」セクションで次のようにします。

予約語「!」がパイプの前に来る場合、終了状態は上記の終了状態の論理的否定です。

一方[ ! … ]、 を意味しますtest ! …。これはテストで式を否定するという意味です。また見てください!man test

   ! EXPRESSION
          EXPRESSION is false

だから別の意味を持つことができます。複雑な式がある場合、否定は式の一部でのみ機能できます。

あなたが好きなものはあなた次第です。

関連情報