¿La sintaxis de la materia no es igual?

22

Cuando escribo, generalmente escribo mis ifs con la siguiente sintaxis, ya que me resulta más fácil entender que lo que viene a continuación no es cierto.

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

Otros dicen que el camino a continuación es mejor

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

La cuestión es cuando pregunto por qué y si hay diferencias, nadie parece tener una respuesta.

Entonces, ¿hay alguna diferencia entre las dos sintaxis? ¿Es uno de ellos más seguro que el otro? ¿O es solo una cuestión de preferencia / hábito?

Jimmy_A
fuente
99
En el primer caso lo que necesita saber operadores prioridad para distinguir !(x==y)entre (!x)==y.
jimmij
@jimmij ¿Quiere decir que al comparar una cadena esto se if [ ! "$string" = "one" ]traduce si no es el valor de $stringigual one? ¿Y esto se if [ "$string" != "one"]traduce en si el valor de $stringno es igual a one?
Jimmy_A
55
@ Jimmy_A Quiero decir que necesitas saber cómo se "traduce" esto. Reunir operadores ( !=sintaxis) es simplemente más obvio.
jimmij
Estimados votantes cercanos, la respuesta de Stéphane muestra que hay una diferencia material en el comportamiento, la respuesta correcta no está basada en ninguna opinión.
Kevin

Respuestas:

35

Además de los argumentos cosméticos / de preferencia, una razón podría ser que hay más implementaciones donde [ ! "$a" = "$b" ]falla en casos de esquina que con [ "$a" != "$b" ].

Ambos casos deberían ser seguros si las implementaciones siguen el algoritmo POSIX , pero incluso hoy (a principios de 2018 a partir de la escritura), todavía hay implementaciones que fallan. Por ejemplo, con a='(' b=')':

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

Con dashversiones anteriores a 0.5.9, como la 0.5.8 encontrada como shen Ubuntu 16.04 por ejemplo:

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

(corregido en 0.5.9, consulte https://www.mail-archive.com/[email protected]/msg00911.html )

Esas implementaciones se tratan [ ! "(" = ")" ]como [ ! "(" "text" ")" ]es [ ! "text" ](prueba si "texto" es la cadena nula) mientras POSIX lo obliga a ser [ ! "x" = "y" ](prueba "x" e "y" para la igualdad). Esas implementaciones fallan porque realizan la prueba incorrecta en ese caso.

Tenga en cuenta que todavía hay otra forma:

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

Ese requiere un shell POSIX (no funcionará con el antiguo shell Bourne).

Tenga en cuenta que varias implementaciones también han tenido problemas con [ "$a" = "$b" ](y [ "$a" != "$b" ]) y todavía les gusta la [creación de /bin/shSolaris 10 (un shell Bourne, estando el shell POSIX /usr/xpg4/bin/sh). Por eso ves cosas como:

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

En scripts que intentan ser portables a sistemas antiguos.

Stéphane Chazelas
fuente
En otras palabras, ambas sintaxis hacen lo mismo, sin diferencias en absoluto, pero ! "$a" = "b"deben ser más cuidadosos con la forma en que la escriben para especificar la comparación. Por su ejemplo, entiendo que el segundo comando regresa, lo not zeroque podría ser beneficioso o problemático. Podría ser beneficioso si desea salir si no coinciden, o preocuparse si desea ver si la comparación se estrelló
Jimmy_A
2
@Jimmy_A, no, en esas implementaciones [ ! "$a" = "$b" ]simplemente falla cuando $aes (y $bes ), afirma que son idénticas cuando no lo son, (no es la misma cadena que ), pero [realiza la prueba incorrecta en ese caso.
Stéphane Chazelas
Ahhh, creo que lo tengo. El primero y el tercero significan verificar si la condición es verdadera, mientras que el segundo y el cuarto si la condición es falsa. Por lo tanto, los códigos de estado de salida son diferentes. Básicamente dice que las variables 1 y 4 son diferentes y que 2 y 3 no son iguales.
Jimmy_A
3
@Jimmy_A, no. Has perdido completamente el punto. Si estas implementaciones siguieran a POSIX, entonces todos los códigos de estado serían 0.
Comodín el
Para asegurarme de que entiendo, esto se reduce a: a [ ! "$a" = "$b" ]veces se maneja incorrectamente en implementaciones de shell con errores (lo que creo que es más o menos reformular la primera oración de la respuesta).
Michael Burr el
8

La x != ysintaxis es mejor porque ! x == yes propensa a errores: requiere el conocimiento de la precedencia de los operadores que difiere de un idioma a otro. La sintaxis ! x == ypodría interpretarse como !(x == y)o (!x) == y, dependiendo de la prioridad de !frente =.


Por ejemplo, en la c++negación ! viene antes del operador de comparación / relacional == , de ahí el siguiente código:

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

devoluciones

true
false
true
false

Se puede observar un comportamiento similar en muchos otros idiomas, incluido, por ejemplo awk, una herramienta de uso frecuente en el mundo Unix.


Por otro lado, reunir a los operadores a través de x != yno genera confusión como un patrón bien establecido. Además, técnicamente hablando, a !=menudo no son dos, sino un solo operador, por lo que debería ser incluso más rápido de evaluar que una comparación separada y luego la negación. Por lo tanto, aunque ambas sintaxis funcionan en bash, recomendaría seguirlas, x != yya que es mucho más fácil leer y mantener el código que sigue cierta lógica estándar.

jimmij
fuente
4

Este tipo de cosas está muy basado en la opinión, ya que la "respuesta" depende en gran medida de la forma en que el cerebro de un individuo está conectado. Si bien es cierto que semánticamente, NOT ( A == B )es idéntico a (A != B )uno, uno podría ser más claro para una persona y el otro para otra. También depende del contexto. Por ejemplo, si tengo un conjunto de indicadores, los significados pueden ser más claros con una sintaxis sobre otra:

if NOT ( fileHandleStatus == FS_OPEN )

Opuesto a

if ( fileHandleStatus != FS_OPEN )
DopeGhoti
fuente
E incluso if ( FS_OPEN != fileHandleStatus )como resultado de la facilidad de escribir accidentalmente en =lugar de ==en lenguajes donde el primero es la asignación y la prueba de igualdad posterior (como C) ...
derobert