¿Por qué no es [-n] falso como [-n ""]?

20

Mi pregunta es sobre los valores de retorno producidos por este código:

if [ -n ]; then echo "true"; else echo "false"; fi

Esto imprime true.

Su prueba complementaria usando [ -z ]también imprime true:

if [ -z ]; then echo "true"; else  echo "false"; fi

En el código anterior, ¿por qué la [ -n ]prueba supone el valor de cadena que no se pasa en absoluto, ya que no es nulo?

Se imprime el siguiente código false. Esto se espera ya que el valor de cadena pasado es nulo y de longitud cero.

if [ -n "" ]; then echo "true"; else  echo "false"; fi
Ravi Kumar
fuente

Respuestas:

14

[x] es equivalente a [ -nx] incluso si x comienza -siempre que no haya operando.

$ [ -o ] ; echo $?
0
$ [ -eq ] ; echo $?
0
$ [ -n -o ] ; echo $?
0
$ [ -n -eq ] ; echo $?
0
Ignacio Vazquez-Abrams
fuente
44
Tenga en cuenta que, históricamente, [ -t ]estaba probando si stdout era un terminal (abreviatura [ -t 1 ]) y algunos shells todavía lo están haciendo (en el caso de que ksh93solo -tsea ​​literal), por lo que es mejor usarlo [ -n "$var" ]que [ "$var" ]. A pesar de eso todavía fallar en algunos viejos testimplementaciones para los valores de $varcomo =, en cuyo caso, [ "" != "$var" ]o [ "x$var" != x ], o case $x in "")...pueden ser mejores.
Stéphane Chazelas
3
Interesante elección de -oaquí. En algunos shells como bash, -oes un operador unario (prueba si se establece una opción) y binario (o), por lo que cosas como [ ! -o monitor ]son ambiguas. ¿Está probando que la monitoropción no está configurada, o que !o bien monitorson cadenas no vacías? Las reglas POSIX deciden: la última (eso es diferente con [[ ! -o monitor ]]).
Stéphane Chazelas
30

[ -n ]No utiliza la -nprueba.

El -nen [ -n ]no es una prueba en absoluto. Cuando solo hay un argumento entre [y ], ese argumento es una cadena que se prueba para ver si está vacía. Incluso cuando esa cadena tiene un encabezado -, todavía se interpreta como un operando, no una prueba. Dado que la cadena -nno está vacía, contiene dos caracteres -y n, no caracteres cero, se [ -n ]evalúa como verdadera.

Como dice Ignacio Vázquez-Abrams , donde stringhay un solo argumento, la prueba realizada stringen es la misma que la realizada en . Cuando sucede ser , no pasa nada especial. El in y el segundo in son simplemente cadenas que se prueban para el vacío.[ string ][ -n string ]string-n-n[ -n ]-n[ -n -n ]

Cuando solo hay un argumento entre [y ], ese argumento siempre es una cadena que se probará para detectar la ausencia de vacíos, incluso si se denomina igual que una prueba. De manera similar, cuando hay dos argumentos entre [y, ]y el primero de ellos es -n, el segundo siempre es una cadena que se probará para detectar la ausencia de vacíos, incluso si resulta que se denomina igual que una prueba. Esto es simplemente porque la sintaxis de [insiste en que un solo argumento entre [y ]después -nes un operando de cadena.

Por la misma razón que [ -n ]no usa la -nprueba, [ -z ]no usa la -zprueba.


Usted puede aprender más acerca [de bashmediante el examen de la ayuda para ello. Tenga en cuenta que es un shell incorporado :

$ type [
[ is a shell builtin

Por lo tanto, puede ejecutar help [para obtener ayuda:

$ help [
[: [ arg... ]
    Evaluate conditional expression.

    This is a synonym for the "test" builtin, but the last argument must
    be a literal `]', to match the opening `['.

Para obtener más información, incluyendo qué pruebas son compatibles y cómo funcionan, tendrá que ver la ayuda test. Cuando ejecute el comando help test, obtendrá una lista detallada. En lugar de reproducirlo todo, esta es la parte sobre los operadores de cadenas:

      -z STRING      True if string is empty.

      -n STRING
         STRING      True if string is not empty.

      STRING1 = STRING2
                     True if the strings are equal.
      STRING1 != STRING2
                     True if the strings are not equal.
      STRING1 < STRING2
                     True if STRING1 sorts before STRING2 lexicographically.
      STRING1 > STRING2
                     True if STRING1 sorts after STRING2 lexicographically.

Observe eso -n STRINGy simplemente STRINGhaga lo mismo: prueban si la cadena STRINGno está vacía.

Eliah Kagan
fuente
2
Buena explicación
Sergiy Kolodyazhnyy
1
Quizás también mencione que esto tiene implicaciones para las variables no citadas que no están establecidas, como esta: paste.ubuntu.com/25831047
Sergiy Kolodyazhnyy
1
@SergiyKolodyazhnyy Creo que podría ser mejor en una respuesta separada. Las variables que no están definidas, o establecidas pero vacías, o que contienen solo IFSespacios en blanco, harán eso; Las variables que contienen varias palabras en lugar de cero producen otro efecto y pueden hacer que se ejecute una prueba completamente diferente. Las cadenas que aparecen literalmente con la intención de ser operandos solo funcionarán correctamente si no contienen espacios o pestañas o si están entre comillas. La respuesta sería mucho más larga y complicada si cubriera este tema de manera accesible. Si decides publicar una respuesta, ¡no dudes en enviarme un mensaje aquí al respecto!
Eliah Kagan
@Eliah Kagan, su respuesta es más completa y detallada, aunque la respuesta de Ignacio Vázquez-Abrams respondió mi pregunta.
Ravi Kumar
1
Creo que te estás perdiendo la razón por la que es y tiene que ser así: si no, [ "$var" ]nunca sería utilizable como prueba porque $varpodría expandirse a -n.
R ..
12

[ -n ]es cierto porque el [comando (también conocido como el testcomando) actúa sobre el número de argumentos que se le da. Si se le da un solo argumento, el resultado es "verdadero" si el argumento es una cadena no vacía. "-n" es una cadena con 2 caracteres, no está vacía, por lo tanto, "verdadero".

Glenn Jackman
fuente