Bedeutung des Fehlers "[: zu viele Argumente" von if [] (eckige Klammern)

211

Ich konnte keine einfache Ressource finden, die die Bedeutung des folgenden BASH-Shell-Fehlers beschreibt und behebt. Daher veröffentliche ich das, was ich nach der Recherche gefunden habe.

Der Fehler:

-bash: [: too many arguments

Google-freundliche Version : bash open square bracket colon too many arguments .

Kontext: Eine if-Bedingung in einzelnen eckigen Klammern mit einem einfachen Vergleichsoperator wie gleich, größer als usw., zum Beispiel:

VARIABLE=$(/some/command);
if [ $VARIABLE == 0 ]; then
  # some action
fi 
user56reinstatemonica8
quelle
1
Wo ist der Code, der diesen speziellen Fehler verursacht hat?
Anderson Green

Antworten:

353

Wenn $VARIABLEes sich um eine Zeichenfolge handelt, die Leerzeichen oder andere Sonderzeichen enthält, und einzelne eckige Klammern verwendet werden (dies ist eine Verknüpfung für den testBefehl), kann die Zeichenfolge in mehrere Wörter aufgeteilt werden. Jedes dieser Argumente wird als separates Argument behandelt.

Damit eine Variable in viele Argumente aufgeteilt wird :

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

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

Gleiches gilt für jeden Funktionsaufruf, der eine Zeichenfolge mit Leerzeichen oder anderen Sonderzeichen aufgibt.


Einfache Lösung

Schließen Sie die Variablenausgabe in doppelte Anführungszeichen ein und zwingen Sie sie, als eine Zeichenfolge zu bleiben (daher ein Argument). Beispielsweise,

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

So einfach ist das. Fahren Sie jedoch mit "Auch Vorsicht ..." fort, wenn Sie nicht garantieren können, dass Ihre Variable keine leere Zeichenfolge oder eine Zeichenfolge ist, die nur Leerzeichen enthält.


Oder ein alternatives fix ist doppelt eckige Klammern zu verwenden (was eine Abkürzung für den IS - new testBefehl).

Dies existiert jedoch nur in Bash (und anscheinend in Korn und Zsh) und ist daher möglicherweise nicht mit Standard-Shells kompatibel, die von /bin/shusw. aufgerufen werden .

Dies bedeutet, dass es auf einigen Systemen möglicherweise von der Konsole auscron funktioniert, jedoch nicht, wenn es an einer anderen Stelle aufgerufen wird, z. B. von , je nachdem, wie alles konfiguriert ist.

Es würde so aussehen:

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

Wenn Ihr Befehl doppelte eckige Klammern wie diese enthält und Sie Fehler in den Protokollen erhalten, diese jedoch über die Konsole funktionieren, versuchen Sie, die [[gegen eine hier vorgeschlagene Alternative auszutauschen, oder stellen Sie sicher, dass für die Ausführung Ihres Skripts eine Shell verwendet wird, die [[aka unterstützt new test.


Achten Sie auch auf den [: unary operator expectedFehler

Wenn der Fehler "Zu viele Argumente" angezeigt wird, erhalten Sie wahrscheinlich eine Zeichenfolge von einer Funktion mit unvorhersehbarer Ausgabe. Wenn es auch möglich ist, eine leere Zeichenfolge (oder alle Leerzeichen) abzurufen, wird dies selbst mit der obigen "Schnellkorrektur" als Nullargument behandelt und schlägt fehl[: unary operator expected

Es ist das gleiche "Gotcha", wenn Sie an andere Sprachen gewöhnt sind - Sie erwarten nicht, dass der Inhalt einer Variablen effektiv in den Code wie dieser gedruckt wird, bevor er ausgewertet wird.

Hier ist ein Beispiel, das sowohl die [: too many argumentsals auch die [: unary operator expectedFehler verhindert: Ersetzen der Ausgabe durch einen Standardwert, wenn sie leer ist (in diesem Beispiel 0), mit doppelten Anführungszeichen um das Ganze:

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

(Hier wird die Aktion ausgeführt, wenn $ VARIABLE 0 oder leer ist. Natürlich sollten Sie die 0 (den Standardwert) in einen anderen Standardwert ändern, wenn ein anderes Verhalten gewünscht wird.)


Schlussbemerkung: Da [es sich um eine Verknüpfung für handelt test, gilt alles oben Genannte auch für den Fehler test: too many arguments(und auch test: unary operator expected)

user56reinstatemonica8
quelle
Ein noch besserer Weg isti=$(some_command); i=$((i)); if [ "$i" == 0 ] ...
Jo So
1
Ich hatte ein Problem, bei dem ein Shellscript, das BASH als Interpreter verwendete, bei Ausführung über Terminal in Ordnung war, bei Ausführung über Crontab jedoch solche Fehler aufwies und lokale E-Mails über Postfix sendete, um diesen Fehler zu melden, und ich stellte fest, dass dies der Fall war eine IF für eine Variable mit Sonderzeichen. Doppelte Anführungszeichen haben mir das Leben gerettet. Danke :)!
Iwanleoncz
13

Ich bin gerade auf diesen Beitrag gestoßen, indem ich den gleichen Fehler erhalten habe und versucht habe zu testen, ob zwei Variablen beide leer (oder nicht leer) sind. Das stellt sich als zusammengesetzter Vergleich heraus - 7.3. Andere Vergleichsoperatoren - Advanced Bash-Scripting Guide ; und ich dachte, ich sollte folgendes beachten:

  • Ich -edachte immer, es bedeutet "leer". aber das bedeutet "Datei existiert" - -zzum Testen der leeren Variablen (Zeichenfolge)
  • String-Variablen müssen in Anführungszeichen gesetzt werden
  • Für den zusammengesetzten logischen UND-Vergleich entweder:
    • benutze zwei tests und &&sie:[ ... ] && [ ... ]
    • oder verwenden Sie den -aOperator in einem einzigen test:[ ... -a ... ]

Hier ist ein funktionierender Befehl (Durchsuchen aller txt-Dateien in einem Verzeichnis und Speichern der gefundenen Dateien grepenthält beide Wörter):

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

Edit 12 Aug 2013: Zugehöriger Problemhinweis:

Beachten Sie, dass , wenn Zeichenfolge Gleichheit mit klassischen Prüfung test(Einzel eckige Klammer [), man muss einen Raum zwischen dem „gleich“ Betreiber haben, die in diesem Fall eine einzige ist „gleich“ =Zeichen (obwohl zwei Gleichen Zeichen ==scheinen , als Gleichheit in Kauf genommen werden Betreiber auch). Dies schlägt also (lautlos) fehl:

$ 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

... aber füge den Platz hinzu - und alles sieht gut aus:

$ 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
quelle
Könnten Sie ein Beispiel für eine Bash-Shell liefern ((A || B) && C)?
JWW
siehe Frage 3826425 und 14964805
splaisan
Dies ist für eine Antwort wirklich nicht so nützlich, da es Ihnen nicht zeigt, wie Sie den Befehl vollständig in eckigen Klammern einfügen können, was beispielsweise erforderlich ist, wenn eine Schleife vorhanden ist.
Timothy Swan
5

Ein weiteres Szenario, das Sie [: too many argumentsoder [: a: binary operator expectedFehler erhalten können, ist, wenn Sie versuchen, alle Argumente zu testen"$@"

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

Es funktioniert richtig, wenn Sie anrufen foo.shoder foo.sh arg1. Wenn Sie jedoch mehrere Argumente wie übergeben foo.sh arg1 arg2, erhalten Sie Fehler. Dies liegt daran, dass es erweitert wird [ -z arg1 arg2 ], was keine gültige Syntax ist.

Der richtige Weg, um das Vorhandensein von Argumenten zu überprüfen, ist [ "$#" -eq 0 ]. ( $#ist die Anzahl der Argumente).

wisbucky
quelle
2

Einige Male Wenn Sie versehentlich die Tastatur berühren und ein Leerzeichen entfernen.

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

Löst diese Fehlermeldung aus. Beachten Sie das Leerzeichen vor ']'.

Kemin Zhou
quelle
1
Ich denke, das führt zu einem anderen Syntaxfehler, wie zum Beispiel: Zeile 21: [: fehlt `] '
Joe Holloway
1

Ich hatte das gleiche Problem mit meinen Skripten. Aber als ich einige Modifikationen vorgenommen habe, hat es bei mir funktioniert. Mir hat das gefallen: -

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

Auf diese Weise habe ich mein Problem gelöst. Hoffe das hilft dir auch.

Kidane
quelle