Significado do erro "[: muitos argumentos" de if [] (colchetes)

211

Não consegui encontrar nenhum recurso simples e simples explicitando o significado e a correção do seguinte erro de shell BASH, por isso estou postando o que encontrei depois de pesquisá-lo.

O erro:

-bash: [: too many arguments

Versão Google-friendly: bash open square bracket colon too many arguments .

Contexto: uma condição if entre colchetes simples com um operador de comparação simples como igual a, maior que etc, por exemplo:

VARIABLE=$(/some/command);
if [ $VARIABLE == 0 ]; then
  # some action
fi 
user56reinstatemonica8
fonte
1
Onde está o código que produziu esse erro específico?
Anderson Green

Respostas:

353

Se $VARIABLEfor uma sequência contendo espaços ou outros caracteres especiais, e colchetes simples forem usados (que é um atalho para o testcomando), a sequência poderá ser dividida em várias palavras. Cada um deles é tratado como um argumento separado.

Para que uma variável seja dividida em vários argumentos :

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

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

O mesmo vale para qualquer chamada de função que coloque uma string contendo espaços ou outros caracteres especiais.


Correção fácil

Coloque a saída variável entre aspas duplas, forçando-a a permanecer como uma sequência (portanto, um argumento). Por exemplo,

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

Simples assim. Mas pule para "Também tome cuidado ..." abaixo se você também não puder garantir que sua variável não será uma sequência vazia ou uma sequência que não contenha nada além de espaço em branco.


Ou, uma correção alternativa é usar colchetes duplos (que é um atalho para o new testcomando).

Porém, isso existe apenas no bash (e aparentemente korn e zsh) e, portanto, pode não ser compatível com os shells padrão chamados por /bin/shetc.

Isso significa que em alguns sistemas, ele pode funcionar no console, mas não quando chamado em outro lugar, como emcron , dependendo de como tudo está configurado.

Seria assim:

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

Se o seu comando contiver colchetes duplos como esse e você receber erros nos logs, mas funcionar no console, tente trocar a [[alternativa sugerida aqui ou verifique se o que executa o script usa um shell que suporte[[ aka new test.


Também tenha cuidado com o [: unary operator expected erro

Se você estiver vendo o erro "muitos argumentos", é provável que esteja obtendo uma string de uma função com saída imprevisível. Se também for possível obter uma string vazia (ou toda a string de espaço em branco), isso seria tratado como zero argumento, mesmo com a "correção rápida" acima, e falharia com[: unary operator expected

É a mesma 'pegadinha' se você estiver acostumado a outros idiomas - não espera que o conteúdo de uma variável seja efetivamente impresso no código como este antes de ser avaliado.

Aqui está um exemplo que impede [: too many argumentsos [: unary operator expectederros e: substituir a saída por um valor padrão se estiver vazio (neste exemplo 0), com aspas duplas em volta da coisa toda:

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

(aqui, a ação ocorrerá se $ VARIABLE for 0 ou vazio. Naturalmente, você deve alterar 0 (o valor padrão) para um valor padrão diferente se um comportamento diferente for desejado)


Nota final: como [é um atalho para test, tudo acima também é verdadeiro para o erro test: too many arguments(e também test: unary operator expected)

user56reinstatemonica8
fonte
Uma maneira ainda melhor éi=$(some_command); i=$((i)); if [ "$i" == 0 ] ...
Jo So
1
Ocorreu um problema em que um Shellscript usando BASH como intérprete, quando executado via terminal, estava indo bem, mas quando executado via Crontab, estava tendo falhas como essa e enviando email local via Postfix, informando esse erro e eu descobri que havia um IF para uma variável que tinha caracteres especiais. Aspas duplas salvaram minha vida. Obrigado :)!
Ivanleoncz
13

Apenas batido para este post, por recebendo o mesmo erro, tentando testar se duas variáveis são tanto vazio (ou não-vazia). Isso acaba sendo um comparação composta - 7.3. Outros operadores de comparação - Advanced Bash-Scripting Guide ; e pensei em observar o seguinte:

  • Eu costumava -epensar que significa "vazio" a princípio; mas isso significa "arquivo existe" - use -zpara testar a variável vazia (string)
  • Variáveis ​​de string precisam ser citadas
  • Para comparação lógica E composta, ou:
    • usar dois tests e&& eles:[ ... ] && [ ... ]
    • ou use o -aoperador em um único test:[ ... -a ... ]

Aqui está um comando funcional (pesquisando todos os arquivos txt em um diretório e despejando os que grepencontrarem contêm duas palavras):

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

Editar 12 de agosto de 2013: nota de problema relacionada:

Observe que, ao verificar a igualdade das cordas com o clássico test(colchete simples [), você DEVE ter um espaço entre o operador "é igual", que neste caso é um único =sinal de "iguais" (embora dois sinais de iguais ==pareçam ser aceitos como igualdade) operador também). Assim, isso falha (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

... mas adicione o espaço - e tudo ficará bem:

$ 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
fonte
Você poderia fornecer um exemplo de shell bash ((A || B) && C)?
JWW
consulte questão 3826425 e 14964805
splaisan
Isso realmente não é útil para uma resposta, porque não mostra como conter o comando completamente entre colchetes, o que é necessário se houver um loop, por exemplo.
Timothy Swan
5

Outro cenário que você pode obter o [: too many argumentsou [: a: binary operator expectederros é se você tentar teste para todos os argumentos"$@"

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

Funciona corretamente se você ligar foo.shou foo.sh arg1. Mas se você passar vários argumentos foo.sh arg1 arg2, receberá erros. Isso ocorre porque está sendo expandido para[ -z arg1 arg2 ] , o que não é uma sintaxe válida.

A maneira correta de verificar a existência de argumentos é [ "$#" -eq 0 ]. ( $#é o número de argumentos).

wisbucky
fonte
2

Algumas vezes Se você tocar no teclado acidentalmente e remover um espaço.

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

Irá disparar essa mensagem de erro. Observe o espaço antes de ']' ser necessário.

Kemin Zhou
fonte
1
Eu acho que isso resulta em um erro de sintaxe diferente, como: linha 21: [: falta de]]
933 Joe Holloway
1

Eu tive o mesmo problema com meus scripts. Mas quando eu fiz algumas modificações, funcionou para mim. Eu fiz assim: -

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

Dessa forma, resolvi meu problema. Espero que ajude você também.

Kidane
fonte