La sintassi della non uguale importa?


22

Quando scrivo, di solito scrivo i miei if con la seguente sintassi in quanto è più facile per me capire che ciò che verrà dopo non è vero.

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

Altri dicono che la strada qui sotto è migliore

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

Il fatto è quando chiedo perché e se ci sono differenze, nessuno sembra avere alcuna risposta.

Quindi, ci sono differenze tra le due sintassi? Uno è più sicuro dell'altro? O è solo una questione di preferenza / abitudine?


9
Nel primo caso è necessario conoscere gli operatori la priorità per distinguere !(x==y)da (!x)==y.
Jimmij,

@jimmij Vuoi dire che quando si confronta una stringa questo si if [ ! "$string" = "one" ]traduce in se non il valore di $stringuguale one. E questo si if [ "$string" != "one"]traduce in se il valore di $stringnon è uguale a one?
Jimmy_A,

5
@Jimmy_A Voglio dire che devi sapere come questo "si traduce". Riunire gli operatori ( !=sintassi) è semplicemente più ovvio.
Jimmij,

Cari elettori stretti, la risposta di Stéphane mostra che c'è una differenza materiale nel comportamento, la risposta corretta non è in alcun modo basata sull'opinione.
Kevin,

Risposte:


35

Oltre agli argomenti cosmetici / di preferenza, una ragione potrebbe essere che ci sono più implementazioni in cui [ ! "$a" = "$b" ]fallisce in casi angolari che con [ "$a" != "$b" ].

Entrambi i casi dovrebbero essere sicuri se le implementazioni seguono l'algoritmo POSIX , ma anche oggi (inizio 2018 al momento della stesura), ci sono ancora implementazioni che falliscono. Ad esempio, con a='(' b=')':

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

Con dashversioni precedenti alla 0.5.9, come la 0.5.8 trovata come shsu Ubuntu 16.04 per esempio:

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

(risolto in 0.5.9, consultare https://www.mail-archive.com/dash@vger.kernel.org/msg00911.html )

Queste implementazioni trattano [ ! "(" = ")" ] come [ ! "(" "text" ")" ]cioè [ ! "text" ](test se "testo" è la stringa nulla) mentre mandati POSIX che sia [ ! "x" = "y" ](test "x" e "y" per l'uguaglianza). Tali implementazioni falliscono perché eseguono il test sbagliato in quel caso.

Nota che c'è ancora un altro modulo:

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

Quello richiede una shell POSIX (non funzionerà con la vecchia shell Bourne).

Notare che anche diverse implementazioni hanno avuto problemi con [ "$a" = "$b" ](e [ "$a" != "$b" ]) e continuano a [piacersi il built-in di /bin/shSolaris 10 (una shell Bourne, la shell POSIX è in /usr/xpg4/bin/sh). Ecco perché vedi cose come:

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

Negli script cercando di essere portabile su vecchi sistemi.


Quindi, in altre parole, entrambe le sintassi fanno lo stesso, nessuna differenza, ma con ! "$a" = "b"te devi essere più attento a come lo scrivi per specificare il confronto. Dal tuo esempio capisco che il secondo comando ritorna not zeroche potrebbe essere utile o preoccupante. Potrebbe essere utile se vuoi uscire se non corrispondono, o preoccuparti se vuoi vedere se il confronto è
andato in

2
@Jimmy_A, no, in quelle implementazioni [ ! "$a" = "$b" ]falliscono solo quando $aè (ed $bè ), afferma che sono identiche quando non lo sono, (non è la stessa stringa di ), ma [esegue il test sbagliato in quel caso.
Stéphane Chazelas,

Ahhh, penso di averlo capito. Il primo e il terzo significano verificare se la condizione è vera, mentre il secondo e il quarto se la condizione è falsa. Pertanto, i codici di stato di uscita sono diversi. In pratica dice che 1 e 4 variabili sono diverse e 2 e 3 non uguali.
Jimmy_A

3
@Jimmy_A, no. Hai completamente perso il punto. Se queste implementazioni seguissero POSIX, tutti i codici di stato sarebbero 0.
jolly

Per essere sicuro di aver capito, questo si riduce a: a [ ! "$a" = "$b" ]volte viene gestito in modo errato nelle implementazioni di buggy shell (che credo stia più o meno riaffermando la prima frase della risposta).
Michael Burr,

8

La x != ysintassi è migliore perché ! x == ysoggetta a errori - richiede la conoscenza della precedenza degli operatori che differisce da una lingua all'altra. La sintassi ! x == ypotrebbe essere interpretata come !(x == y)o (!x) == y, a seconda delle priorità !vs =.


Ad esempio, in c++negazione ! viene prima dell'operatore di confronto / relazione == , quindi il seguente codice:

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

ritorna

true
false
true
false

Un comportamento simile può essere osservato in molte altre lingue, incluso ad esempio awkuno strumento di uso frequente nel mondo Unix.


D'altro canto, riunire gli operatori insieme x != ynon crea confusione come modello consolidato. Inoltre, tecnicamente parlando non !=è spesso due, ma solo un operatore, quindi dovrebbe essere anche leggermente più veloce da valutare rispetto al confronto separato e quindi alla negazione. Quindi, sebbene entrambe le sintassi funzionino in bash, consiglierei di seguirlo x != yin quanto è molto più facile leggere e mantenere il codice che segue una logica standard.


4

Questo genere di cose è molto basato sull'opinione, poiché la "risposta" dipende fortemente dal modo in cui il cervello di un individuo sembra essere collegato. Mentre è vero che semanticamente, NOT ( A == B )è identico a (A != B ), uno potrebbe essere più chiaro a una persona e l'altro a un'altra. Dipende anche dal contesto. Ad esempio, se ho un flag impostato, i significati potrebbero essere più chiari con una sintassi su un'altra:

if NOT ( fileHandleStatus == FS_OPEN )

al contrario di

if ( fileHandleStatus != FS_OPEN )

E anche if ( FS_OPEN != fileHandleStatus )a causa della facilità di scrittura accidentale =anziché ==in lingue in cui la prima è assegnazione e il successivo test di uguaglianza (come C) ...
derobert
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.