Significado del error "[: demasiados argumentos" de if [] (corchetes)

212

No pude encontrar ningún recurso simple y sencillo que explique el significado y la solución para el siguiente error de shell BASH, así que estoy publicando lo que encontré después de investigarlo.

El error:

-bash: [: too many arguments

Versión de los requisitos de Google: bash open square bracket colon too many arguments .

Contexto: una condición if entre corchetes simples con un operador de comparación simple como igual, mayor que etc., por ejemplo:

VARIABLE=$(/some/command);
if [ $VARIABLE == 0 ]; then
  # some action
fi 
user56reinstatemonica8
fuente
1
¿Dónde está el código que produjo este error específico?
Anderson Green

Respuestas:

354

Si su $VARIABLEes una cadena que contiene espacios u otros caracteres especiales, y se utilizan corchetes individuales (que es un atajo para el testcomando), entonces la cadena se puede dividir en varias palabras. Cada uno de estos se trata como un argumento separado.

Para que una variable se divida en muchos argumentos :

VARIABLE=$(/some/command);  
# returns "hello world"

if [ $VARIABLE == 0 ]; then
  # fails as if you wrote:
  # if [ hello world == 0 ]
fi 

Lo mismo será cierto para cualquier llamada de función que ponga una cadena que contenga espacios u otros caracteres especiales.


Arreglo fácil

Envuelva la salida variable entre comillas dobles, forzándola a permanecer como una cadena (por lo tanto, un argumento). Por ejemplo,

VARIABLE=$(/some/command);
if [ "$VARIABLE" == 0 ]; then
  # some action
fi 

Simple como eso. Pero pase a "También tenga cuidado ..." a continuación si tampoco puede garantizar que su variable no sea una cadena vacía, o una cadena que no contenga más que espacios en blanco.


O, una solución alternativa es usar corchetes dobles (que es un atajo para el new testcomando).

Sin embargo, esto solo existe en bash (y aparentemente korn y zsh), por lo que puede no ser compatible con shells predeterminados llamados por /bin/shetc.

Esto significa que en algunos sistemas, podría funcionar desde la consola, pero no cuando se llama a otra parte, como desdecron , dependiendo de cómo esté configurado todo.

Se vería así:

VARIABLE=$(/some/command);
if [[ $VARIABLE == 0 ]]; then
  # some action
fi 

Si su comando contiene corchetes dobles como este y obtiene errores en los registros pero funciona desde la consola, intente cambiar el [[por una alternativa sugerida aquí, o asegúrese de que todo lo que se ejecute en su script use un shell que sea compatible con [[aka new test.


También ten cuidado con el [: unary operator expectederror

Si ve el error "demasiados argumentos", es probable que obtenga una cadena de una función con salida impredecible. Si también es posible obtener una cadena vacía (o toda la cadena de espacios en blanco), esto se trataría como cero argumentos incluso con la "solución rápida" anterior, y fallaría con[: unary operator expected

Es el mismo 'problema' si estás acostumbrado a otros idiomas: no esperas que el contenido de una variable se imprima efectivamente en el código como este antes de que se evalúe.

Aquí hay un ejemplo que evita [: too many argumentslos [: unary operator expectederrores y los errores: reemplazar la salida con un valor predeterminado si está vacío (en este ejemplo, 0), con comillas dobles alrededor de todo:

VARIABLE=$(/some/command);
if [ "${VARIABLE:-0}" == 0 ]; then
  # some action
fi 

(aquí, la acción ocurrirá si $ VARIABLE es 0, o está vacío. Naturalmente, debe cambiar el 0 (el valor predeterminado) a un valor predeterminado diferente si se desea un comportamiento diferente)


Nota final: dado que [es un atajo para test, todo lo anterior también es cierto para el error test: too many arguments(y también test: unary operator expected)

user56reinstatemonica8
fuente
Una forma aún mejor esi=$(some_command); i=$((i)); if [ "$i" == 0 ] ...
Jo So
1
Experimenté un problema en el que un Shellscript que usaba BASH como intérprete, cuando se ejecutaba a través de la terminal, funcionaba bien, pero cuando se ejecutaba a través de Crontab, tenía fallas como esta y enviaba un correo electrónico local a través de Postfix, informando este error y descubrí que había un IF para una variable que tenía caracteres especiales. Las comillas dobles me salvaron la vida. Gracias :)!
ivanleoncz
13

Sólo topado con este post, consiguiendo el mismo error, tratando de prueba si dos variables son tanto vacía (o no vacía). Eso resulta ser una comparación compuesta - 7.3. Otros operadores de comparación: Guía avanzada de secuencias de comandos Bash ; y pensé que debería tener en cuenta lo siguiente:

  • Solía -epensar que significa "vacío" al principio; pero eso significa "el archivo existe" - utilícelo -zpara probar la variable vacía (cadena)
  • Las variables de cadena deben ser citadas
  • Para la comparación AND lógica compuesta, ya sea:
    • use dos testsy &&ellos:[ ... ] && [ ... ]
    • o use el -aoperador en un solo test:[ ... -a ... ]

Aquí hay un comando de trabajo (buscando en todos los archivos txt en un directorio y volcando los que grepcontienen dos palabras):

find /usr/share/doc -name '*.txt' | while read file; do \
  a1=$(grep -H "description" $file); \
  a2=$(grep -H "changes" $file); \
  [ ! -z "$a1" -a ! -z "$a2"  ] && echo -e "$a1 \n $a2" ; \
done

Edición del 12 de agosto de 2013: nota del problema relacionado:

Tenga en cuenta que al verificar la igualdad de la cadena con el clásico test(corchete simple [), DEBE tener un espacio entre el operador "es igual", que en este caso es un solo =signo "igual" (aunque dos signos iguales ==parecen ser aceptados como igualdad operador también). Por lo tanto, esto falla (en silencio):

$ if [ "1"=="" ] ; then echo A; else echo B; fi 
A
$ if [ "1"="" ] ; then echo A; else echo B; fi 
A
$ if [ "1"="" ] && [ "1"="1" ] ; then echo A; else echo B; fi 
A
$ if [ "1"=="" ] && [ "1"=="1" ] ; then echo A; else echo B; fi 
A

... pero agrega el espacio, y todo se ve bien:

$ if [ "1" = "" ] ; then echo A; else echo B; fi 
B
$ if [ "1" == "" ] ; then echo A; else echo B; fi 
B
$ if [ "1" = "" -a "1" = "1" ] ; then echo A; else echo B; fi 
B
$ if [ "1" == "" -a "1" == "1" ] ; then echo A; else echo B; fi 
B
sdaau
fuente
¿Podría proporcionar un ejemplo de bash shell de ((A || B) && C)?
jww
consulte las preguntas 3826425 y 14964805
splaisan el
Esto realmente no es una respuesta tan útil porque no muestra cómo contener el comando completamente dentro de los corchetes, lo cual es necesario si hay un bucle, por ejemplo.
Timothy Swan el
5

Otro escenario que puede obtener [: too many argumentso [: a: binary operator expectederrores es si intenta probar todos los argumentos"$@"

if [ -z "$@" ]
then
    echo "Argument required."
fi

Funciona correctamente si llamas foo.sho foo.sh arg1. Pero si pasa varios argumentos como foo.sh arg1 arg2, obtendrá errores. Esto se debe a que se está expandiendo a [ -z arg1 arg2 ], que no es una sintaxis válida.

La forma correcta de verificar la existencia de argumentos es [ "$#" -eq 0 ]. ( $#es el número de argumentos).

Wisbucky
fuente
2

Algunas veces si toca el teclado accidentalmente y elimina un espacio.

if [ "$myvar" = "something"]; then
    do something
fi

Activará este mensaje de error. Tenga en cuenta que se requiere el espacio antes de ']'.

Kemin Zhou
fuente
1
Creo que eso produce un error de sintaxis diferente, como: línea 21: [: missing `] '
Joe Holloway
1

He tenido el mismo problema con mis scripts. Pero cuando hice algunas modificaciones funcionó para mí. Me gustó esto: -

export k=$(date "+%k");
if [ $k -ge 16 ] 
    then exit 0; 
else 
    echo "good job for nothing"; 
fi;

De esa manera resolví mi problema. Espero que eso también te ayude.

Kidane
fuente