Solución:
Si tu $VARIABLE
es una cadena que contiene espacios u otros caracteres especiales, y se utilizan corchetes simples (que es un atajo para test
comando), la cadena se puede dividir en varias palabras. Cada uno de estos se trata como un argumento separado.
Así que eso 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 será cierto para cualquier llamada a función que coloque 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 vaya 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 nada más que espacios en blanco.
O un solución alternativa es utilizar corchetes dobles (que es un atajo para la new test
mando).
Sin embargo, esto solo existe en bash (y aparentemente 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, podría funcionar desde la consola, pero no cuando se llama en otro lugar, como desde cron
, 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 [[
for an alternative suggested here, or, ensure that whatever runs your script uses a shell that supports [[
aka new test
.
Also beware of the [: unary operator expected
error
If you’re seeing the “too many arguments” error, chances are you’re getting a string from a function with unpredictable output. If it’s also possible to get an empty string (or all whitespace string), this would be treated as zero arguments even with the above “quick fix”, and would fail with [: unary operator expected
It’s the same ‘gotcha’ if you’re used to other languages – you don’t expect the contents of a variable to be effectively printed into the code like this before it is evaluated.
Here’s an example that prevents both the [: too many arguments
and the [: unary operator expected
errors: replacing the output with a default value if it is empty (in this example, 0
), with double quotes wrapped around the whole thing:
VARIABLE=$(/some/command);
if [ "${VARIABLE:-0}" == 0 ]; entonces # algo de acción 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: Ya que [
is a shortcut for test
, all the above is also true for the error test: too many arguments
(and also test: unary operator expected
)
Just bumped into this post, by getting the same error, trying to test if two variables are both empty (or non-empty). That turns out to be a compound comparison – 7.3. Other Comparison Operators – Advanced Bash-Scripting Guide; and I thought I should note the following:
- I used
thinking it means “empty” at first; but that means “file exists” – use-e
-z
for testing empty variable (string) - String variables need to be quoted
- For compound logical AND comparison, either:
- use two
test
s and&&
them:[ ... ] && [ ... ]
- o usa el
-a
operador en un solotest
:[ ... -a ... ]
- use two
Aquí hay un comando de trabajo (buscando en todos los archivos txt en un directorio y volcando aquellos que grep
los hallazgos 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 12 de agosto de 2013: nota de problema relacionado:
Tenga en cuenta que al comprobar la igualdad de cadenas con classic test
(corchete simple [
), you MUST have a space between the “is equal” operator, which in this case is a single “equals” =
sign (although two equals’ signs ==
seem to be accepted as equality operator too). Thus, this fails (silently):
$ if [ "1"=="" ] ; luego echo A; de lo contrario echo B; fi A $ si [ "1"="" ] ; luego echo A; de lo contrario echo B; fi A $ si [ "1"="" ] && [ "1"="1" ] ; luego echo A; de lo contrario echo B; fi A $ si [ "1"=="" ] && [ "1"=="1" ] ; luego echo A; de lo contrario echo B; fi A
… pero agregue 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 el [: too many arguments
or [: a: binary operator expected
errors is if you try to test for all arguments "[email protected]"
if [ -z "[email protected]" ]
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).