Significado del error "[: demasiados argumentos" de if [] (corchetes)
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
Si $VARIABLE
es una cadena que contiene espacios u otros caracteres especiales y se utilizan corchetes simples (que es un atajo para el test
comando), 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 test
comando).
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/sh
etc.
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 expected
error.
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 arguments
los 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
)
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
pensar que significa "vacío"; pero eso significa que "el archivo existe": utilícelo-e
-z
para probar una variable vacía (cadena) - Las variables de cadena deben citarse
- Para una comparación AND lógica compuesta, ya sea:
- usa dos
test
s y&&
ellos:[ ... ] && [ ... ]
- o utilizar el
-a
operador en un solotest
:[ ... -a ... ]
- usa dos
Aquí hay un comando que funciona (busca en todos los archivos txt en un directorio y descarta los que grep
encuentra 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
Otro escenario en el que puede obtener errores [: too many arguments
o [: a: binary operator expected
es si intenta probar todos los argumentos."$@"
if [ -z "$@" ]
then
echo "Argument required."
fi
Funciona correctamente si llamas foo.sh
o 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).