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

Resuelto user56reinstatemonica8 asked hace 11 años • 6 respuestas

No pude encontrar ningún recurso simple y directo que explique el significado y solucione el siguiente error del shell BASH, así que publicaré lo que encontré después de investigarlo.

El error:

-bash: [: too many arguments

Versión compatible con 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 avatar Dec 09 '12 02:12 user56reinstatemonica8
Aceptado

Si $VARIABLEes una cadena que contiene espacios u otros caracteres especiales y se utilizan corchetes simples (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.

De modo que una variable se divide 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 ocurrirá con cualquier llamada a función que escriba una cadena que contenga espacios u otros caracteres especiales.


arreglo fácil

Envuelva la salida de la variable entre comillas dobles, obligá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 salte a "También tenga cuidado..." a continuación si tampoco puede garantizar que su variable no será una cadena vacía o una cadena que no contenga nada más que espacios en blanco.


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

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

Esto significa que en algunos sistemas, puede funcionar desde la consola, pero no cuando se llama desde otro lugar, 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 lo que ejecute su script use un shell que admita [[aka new test.


Cuidado también con el [: unary operator expectederror.

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

Es lo mismo si estás acostumbrado a otros lenguajes: no esperas que el contenido de una variable se imprima efectivamente en el código de esta manera antes de evaluarlo.

Aquí hay un ejemplo que previene [: too many argumentslos errores y [: unary operator expected: 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 desea un comportamiento diferente)


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

user56reinstatemonica8 avatar Dec 08 '2012 19:12 user56reinstatemonica8

Acabo de encontrarme con esta publicación y obtuve el mismo error al intentar probar si dos variables están vacías (o no vacías). Esto 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:

  • Al principio solía -epensar que significa "vacío"; pero eso significa que "el archivo existe": utilícelo -zpara probar una variable vacía (cadena)
  • Las variables de cadena deben citarse
  • Para una comparación AND lógica compuesta, ya sea:
    • usa dos tests y &&ellos:[ ... ] && [ ... ]
    • o utilizar el -aoperador en un solo test:[ ... -a ... ]

Aquí hay un comando que funciona (busca en todos los archivos txt en un directorio y descarta los que grepencuentra que contienen 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 cadenas con el clásico test(corchete simple [), DEBE tener un espacio entre el operador "es igual", que en este caso es un único =signo "igual" (aunque dos signos iguales ==parecen aceptarse como igualdad operador también). Por tanto, esto falla (silenciosamente):

$ 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 avatar May 28 '2013 10:05 sdaau

Otro escenario en el que puede obtener errores [: too many argumentso [: a: binary operator expectedes 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 comprobar la existencia de argumentos es [ "$#" -eq 0 ]. ( $#es el número de argumentos).

wisbucky avatar Aug 06 '2019 23:08 wisbucky