Significato dell'errore "[: troppi argomenti" da if [] (parentesi quadre)


212

Non sono riuscito a trovare nessuna semplice risorsa semplice che spiegasse il significato e correggesse il seguente errore della shell BASH, quindi sto postando ciò che ho trovato dopo averlo cercato.

L'errore:

-bash: [: too many arguments

Versione indicazioni di Google: bash open square bracket colon too many arguments .

Contesto: una condizione if tra parentesi quadre singole con un semplice operatore di confronto come uguale a, maggiore di ecc., Ad esempio:

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

1
Dov'è il codice che ha prodotto questo errore specifico?
Anderson Green,

Risposte:


354

Se la tua $VARIABLEè una stringa contenente spazi o altri caratteri speciali e vengono utilizzate parentesi quadre singole (che è una scorciatoia per il testcomando), la stringa può essere suddivisa in più parole. Ognuno di questi è trattato come un argomento separato.

In modo che una variabile sia suddivisa in molti argomenti :

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

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

Lo stesso vale per qualsiasi chiamata di funzione che inserisce una stringa contenente spazi o altri caratteri speciali.


Soluzione semplice

Avvolgere l'output della variabile tra virgolette doppie, costringendolo a rimanere come una stringa (quindi un argomento). Per esempio,

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

Semplice come quella. Passa a "Attenzione anche ..." di seguito se non puoi anche garantire che la tua variabile non sarà una stringa vuota o una stringa che non contiene altro che spazi bianchi.


In alternativa, una correzione alternativa consiste nell'utilizzare parentesi quadre doppie (che è una scorciatoia per il new testcomando).

Questo esiste solo in bash (e apparentemente korn e zsh) tuttavia, e quindi potrebbe non essere compatibile con le shell predefinite chiamate da /bin/shecc.

Ciò significa che su alcuni sistemi, potrebbe funzionare dalla console ma non quando viene chiamato altrove, come dacron , a seconda di come tutto è configurato.

Sarebbe così:

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

Se il tuo comando contiene parentesi quadre doppie come questa e ottieni errori nei log ma funziona dalla console, prova a scambiare la [[con un'alternativa qui suggerita, oppure assicurati che qualunque cosa esegua il tuo script utilizza una shell che supporta [[aka new test.


Attenzione anche [: unary operator expectedall'errore

Se visualizzi l'errore "troppi argomenti", è probabile che stai ricevendo una stringa da una funzione con output imprevedibile. Se è anche possibile ottenere una stringa vuota (o tutta la stringa degli spazi bianchi), questa verrebbe trattata come argomento zero anche con la "soluzione rapida" precedente e fallirebbe con[: unary operator expected

È lo stesso 'gotcha' se sei abituato ad altre lingue - non ti aspetti che il contenuto di una variabile venga effettivamente stampato nel codice in questo modo prima che venga valutato.

Ecco un esempio che impedisce sia la [: too many argumentse gli [: unary operator expectederrori: sostituendo l'uscita con un valore predefinito se vuoto (in questo esempio, 0), con virgolette avvolto intorno il tutto:

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

(qui l'azione si verificherà se $ VARIABLE è 0 o vuoto. Naturalmente, è necessario modificare lo 0 (valore predefinito) in un valore predefinito diverso se si desidera un comportamento diverso)


Nota finale: poiché [è una scorciatoia per test, tutto quanto sopra vale anche per l'errore test: too many arguments(e anche test: unary operator expected)


Un modo ancora migliore èi=$(some_command); i=$((i)); if [ "$i" == 0 ] ...
Jo So,

1
Ho riscontrato un problema in cui uno shellscript che utilizzava BASH come interprete, quando eseguito tramite terminale, stava andando bene, ma quando eseguito tramite Crontab, stava avendo problemi come questo e inviando e-mail locale via Postfix, informando questo errore e ho capito, che c'era un IF per una variabile che aveva caratteri speciali. Le doppie virgolette mi hanno salvato la vita. Grazie :)!
Ivanleoncz,

13

Ho appena incontrato questo post, ottenendo lo stesso errore, cercando di verificare se due variabili sono entrambe vuote (o non vuote). Questo risulta essere un confronto composto - 7.3. Altri operatori di confronto - Guida avanzata di Bash-Scripting ; e ho pensato che dovrei notare quanto segue:

  • All'inizio -epensavo che significasse "vuoto"; ma ciò significa che "esiste un file": utilizzare -zper testare una variabile vuota (stringa)
  • Le variabili stringa devono essere quotate
  • Per un confronto AND logico composto, sia:
    • usa due testsecondi &&:[ ... ] && [ ... ]
    • o usa l' -aoperatore in un unico test:[ ... -a ... ]

Ecco un comando funzionante (cerca in tutti i file txt in una directory e scarica quelli che greptrova contengono entrambe le due parole):

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

Modifica 12 agosto 2013: nota relativa al problema:

Si noti che quando si controlla l'uguaglianza delle stringhe con il classico test(parentesi quadra singola [), È NECESSARIO avere uno spazio tra l'operatore "è uguale", che in questo caso è un singolo =segno "uguale" (anche se i segni di due uguali ==sembrano essere accettati come uguaglianza operatore anche). Pertanto, ciò non riesce (in silenzio):

$ 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

... ma aggiungi lo spazio e tutto sembra a posto:

$ 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

Potresti fornire un esempio di shell bash di ((A || B) && C)?
JWW

si prega di vedere le domande 3826425 e 14964805
splaisan

Questo non è davvero utile per una risposta perché non mostra come contenere completamente il comando tra parentesi quadre, che è necessario se c'è un ciclo, per esempio.
Timothy Swan,

5

Un altro scenario che è possibile ottenere [: too many argumentso [: a: binary operator expectederrori è se si tenta di verificare tutti gli argomenti"$@"

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

Funziona correttamente se chiami foo.sho foo.sh arg1. Ma se passi più argomenti simili foo.sh arg1 arg2, otterrai errori. Questo perché viene espanso in [ -z arg1 arg2 ], che non è una sintassi valida.

Il modo corretto di verificare l'esistenza di argomenti è [ "$#" -eq 0 ]. ( $#è il numero di argomenti).


2

Alcune volte Se si tocca la tastiera accidentalmente e si rimuove uno spazio.

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

Attiverà questo messaggio di errore. Nota lo spazio prima di ']' è richiesto.


1
Penso che si traduca in un diverso errore di sintassi, come ad esempio: riga 21: [: mancante `] '
Joe Holloway,

1

Ho avuto lo stesso problema con i miei script. Ma quando ho apportato alcune modifiche ha funzionato per me. Mi è piaciuto così: -

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

in quel modo ho risolto il mio problema. Spero che possa aiutare anche per te.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.