web-dev-qa-db-ja.com

等しくない構文は重要ですか?

スクリプトを作成するとき、私は通常、次の構文を使用してifsを記述します。これは、次に来ることが真実ではないことを理解するのが簡単だからです。

if [ ! "$1" = "$2" ]; then

他の人は、以下の方法がより良いと言います

if [ "$1" != "$2" ]; then

問題は私がその理由を尋ねたとき、そして何か違いがあるかどうか、誰も答えを持っているようには見えないことです。

では、2つの構文に違いはありますか?それらの1つは他より安全ですか?それとも好み/習慣の問題ですか?

22
Jimmy_A

化粧品/設定引数のほかに、_[ ! "$a" = "$b" ]_が_[ "$a" != "$b" ]_を使用するよりも、まれなケースで失敗する実装が多いことが1つの理由である可能性があります。

実装が POSIXアルゴリズム に従っていれば、どちらの場合も安全ですが、現在(執筆時点で2018年初頭)でも、失敗する実装があります。たとえば、a='(' b=')'の場合:

_$ (a='(' b=')'; busybox test "$a" != "$b"; echo "$?")
0
$ (a='(' b=')'; busybox test ! "$a" = "$b"; echo "$?")
1
_

0.5.9より前のdashバージョンでは、たとえば、Ubuntu 16.04でshとして検出された0.5.8のように:

_$ a='(' b=')' dash -c '[ "$a" != "$b" ]; echo "$?"'
0
$ a='(' b=')' dash -c '[ ! "$a" = "$b" ]; echo "$?"'
1
_

(0.5.9で修正、 https://www.mail-archive.com/[email protected]/msg00911.html を参照)

これらの実装は[ ! "(" = ")" ][ ! "(" "text" ")" ]として扱い、_[ ! "text" ]_( "text"がnull文字列かどうかをテスト)しますが、POSIXは_[ ! "x" = "y" ]_(test " x "と" y "は等しいことを示します)。その場合、間違ったテストを実行するため、これらの実装は失敗します。

さらに別のフォームがあることに注意してください:

_! [ "$a" = "$b" ]
_

これにはPOSIXシェルが必要です(古いBourneシェルでは動作しません)。

いくつかの実装では_[ "$a" = "$b" ]_(および_[ "$a" != "$b" ]_)にも問題がある であり、Solaris 10の_[_の_/bin/sh_ビルトインと同様に動作することに注意してください。 (ボーンシェル、POSIXシェルは_/usr/xpg4/bin/sh_にあります)。そのため、次のようなものが表示されます。

_[ "x$a" != "x$b" ]
_

古いシステムへの移植を試みているスクリプト。

35

_x != y_構文はエラーが発生しやすいため、_! x == y_構文の方が優れています。言語ごとに異なる演算子の優先順位の知識が必要です。構文_! x == y_は、_(!x) == y_と_!_の優先順位に応じて、!(x == y)または_=_として解釈できます。


たとえば、_c++_否定_!_ 比較/関係演算子の前に来る _==_の場合、次のコードになります。

_#include<iostream>

using namespace std;

int main()
{
  int x=1, y=2;
  if(     x  != y   ) cout<<"true"<<endl; else cout<<"false"<<endl;
  if(  !  x  == y   ) cout<<"true"<<endl; else cout<<"false"<<endl;
  if(  !( x  == y ) ) cout<<"true"<<endl; else cout<<"false"<<endl;
  if(   (!x) == y   ) cout<<"true"<<endl; else cout<<"false"<<endl;
}
_

戻り値

_true
false
true
false
_

同様の動作は、他の多くの言語でも観察できます。 awk-Unixの世界で頻繁に使用されるツール。


一方、_x != y_を介して演算子をまとめることは、十分に確立されたパターンとして混乱を招くことはありません。さらに、技術的に言えば_!=_は2つではなく1つの演算子であることが多いため、個別の比較と否定よりもわずかに高速に評価する必要があります。したがって、どちらの構文もbashで機能しますが、_x != y_に従うことをお勧めします。これは、いくつかの標準ロジックに従うコードを読み、維持する方が簡単だからです。

8
jimmij

このようなことはvery意見ベースです。「答え」は個人の脳がたまたま配線される方法に非常に強く依存するためです。意味的にはNOT ( A == B )(A != B )と同じですが、ある人にとってはより明確になり、別の人にとってはより明確になる場合があります。また、コンテキストに依存します。たとえば、フラグを設定している場合、ある構文を別の構文にすると意味がより明確になる場合があります。

if NOT ( fileHandleStatus == FS_OPEN )

とは対照的に

if ( fileHandleStatus != FS_OPEN )
4
DopeGhoti