Apakah sintaksinya tidak sama dengan materi?

22

Ketika scripting, saya biasanya menulis ifs saya dengan sintaks berikut karena lebih mudah bagi saya untuk memahami bahwa apa yang terjadi selanjutnya tidak benar.

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

Yang lain mengatakan bahwa cara di bawah ini lebih baik

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

Masalahnya adalah ketika saya bertanya mengapa dan apakah ada perbedaan tampaknya tidak ada yang punya jawaban.

Jadi, apakah ada perbedaan antara kedua sintaksis? Apakah salah satunya lebih aman dari yang lain? Atau itu hanya masalah preferensi / kebiasaan?

Jimmy_A
sumber
9
Dalam kasus pertama yang perlu Anda ketahui operator prioritas untuk membedakan !(x==y)dari (!x)==y.
jimmij
@ jimmij Apakah maksud Anda ketika membandingkan string ini artinya if [ ! "$string" = "one" ]jika tidak nilai $stringsama dengan one. Dan ini if [ "$string" != "one"]diterjemahkan menjadi jika nilai $stringtidak sama dengan one?
Jimmy_A
5
@ Jimmy_A Maksud saya Anda perlu tahu bagaimana ini "diterjemahkan". Mengumpulkan operator bersama ( !=sintaksis) lebih jelas.
jimmij
Para pemilih yang dekat, jawaban Stéphane menunjukkan bahwa ada perbedaan materi dalam perilaku, jawaban yang benar tidak berdasarkan opini.
Kevin

Jawaban:

35

Selain argumen kosmetik / preferensi, satu alasan bisa jadi bahwa ada lebih banyak implementasi di mana [ ! "$a" = "$b" ]gagal dalam kasus sudut daripada dengan [ "$a" != "$b" ].

Kedua kasus harus aman jika implementasi mengikuti algoritma POSIX , tetapi bahkan hari ini (awal 2018 saat penulisan), masih ada implementasi yang gagal. Misalnya, dengan a='(' b=')':

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

Dengan dashversi sebelum 0.5.9, seperti 0.5.8 yang ditemukan shdi Ubuntu 16.04 misalnya:

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

(diperbaiki dalam 0,5.9, lihat https://www.mail-archive.com/[email protected]/msg00911.html )

Implementasi tersebut diperlakukan [ ! "(" = ")" ]seperti [ ! "(" "text" ")" ]itu [ ! "text" ](uji apakah "teks" adalah string nol) sementara POSIX mengamanatkannya [ ! "x" = "y" ](uji "x" dan "y" untuk kesetaraan). Implementasi tersebut gagal karena mereka melakukan tes yang salah dalam kasus itu.

Perhatikan bahwa masih ada formulir lain:

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

Yang itu membutuhkan shell POSIX (tidak akan bekerja dengan shell Bourne yang lama).

Perhatikan bahwa beberapa implementasi memiliki masalah dengan [ "$a" = "$b" ](dan [ "$a" != "$b" ]) juga dan masih seperti [builtin /bin/shpada Solaris 10 (shell Bourne, shell POSIX berada di /usr/xpg4/bin/sh). Itu sebabnya Anda melihat hal-hal seperti:

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

Dalam skrip mencoba menjadi portabel untuk sistem lama.

Stéphane Chazelas
sumber
Jadi dengan kata lain, kedua sintaks melakukan hal yang sama, tidak ada perbedaan apa pun, tetapi dengan ! "$a" = "b"Anda harus lebih berhati-hati tentang bagaimana Anda menulisnya untuk menentukan perbandingan. Dari contoh Anda, saya mengerti bahwa perintah kedua kembali not zeroyang bisa bermanfaat atau mengganggu. Ini bisa bermanfaat jika Anda ingin keluar jika mereka tidak cocok, atau menyusahkan jika Anda ingin melihat apakah perbandingannya
macet
2
@Jimmy_A, tidak ada, pada mereka implementasi [ ! "$a" = "$b" ]hanya gagal ketika $aadalah (dan $badalah ), klaim mereka adalah identik ketika mereka tidak, (tidak string sama ), tapi [melakukan tes yang salah dalam kasus itu.
Stéphane Chazelas
Ahhh, kurasa aku mengerti. Yang pertama dan ketiga berarti memeriksa apakah kondisinya benar, sedangkan yang kedua dan keempat jika kondisinya salah. Dengan demikian, kode status keluar menjadi berbeda. Pada dasarnya mengatakan, 1 & 4 variabel berbeda dan 2 & 3 tidak sama.
Jimmy_A
3
@ Jimmy_A, tidak. Anda benar-benar melewatkan intinya. Jika implementasi ini mengikuti POSIX, maka semua kode status akan menjadi 0.
Wildcard
Untuk memastikan saya mengerti, ini bermuara pada: [ ! "$a" = "$b" ]kadang-kadang ditangani dengan tidak benar dalam implementasi buggy shell (yang saya pikir lebih atau kurang menyatakan kembali kalimat pertama dari jawaban).
Michael Burr
8

The x != ysintaks adalah lebih baik karena ! x == yrawan kesalahan - membutuhkan pengetahuan tentang operator didahulukan yang berbeda dari bahasa ke bahasa. Sintaks ! x == ybisa diartikan sebagai !(x == y)atau (!x) == y, tergantung pada prioritas !vs =.


Misalnya, dalam c++negasi ! datang sebelum operator perbandingan / relasional == , maka kode berikut:

#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;
}

kembali

true
false
true
false

Perilaku serupa dapat diamati dalam banyak bahasa lain, termasuk misalnya awk- alat yang sering digunakan di dunia Unix.


Di sisi lain, mengumpulkan operator melalui x != ytidak menyebabkan kebingungan sebagai pola yang mapan. Selain itu, secara teknis !=seringkali bukan hanya dua, tetapi hanya satu operator, sehingga harus lebih cepat untuk mengevaluasi daripada perbandingan yang terpisah dan kemudian negasi. Oleh karena itu, walaupun kedua sintaks bekerja di bash, saya akan merekomendasikan untuk mengikuti x != ykarena lebih mudah untuk membaca dan memelihara kode yang mengikuti beberapa logika standar.

jimmij
sumber
4

Hal semacam ini sangat didasarkan pada opini, karena "jawaban" sangat tergantung pada bagaimana otak seseorang terjadi. Memang benar bahwa secara semantik NOT ( A == B )identik dengan yang (A != B )satu mungkin lebih jelas bagi satu orang dan yang lain bagi orang lain. Ini juga tergantung pada konteks. Misalnya, jika saya memiliki set bendera, artinya mungkin lebih jelas dengan satu sintaks atas yang lain:

if NOT ( fileHandleStatus == FS_OPEN )

sebagai lawan

if ( fileHandleStatus != FS_OPEN )
DopeGhoti
sumber
Dan bahkan if ( FS_OPEN != fileHandleStatus )sebagai akibat dari kemudahan mengetik secara tidak sengaja =alih-alih ==dalam bahasa di mana yang pertama adalah penugasan dan tes kesetaraan yang kemudian (seperti C) ...
derobert