Syntaxfehler in der Nähe des unerwarteten Tokens "fi"

17

Ich möchte nicht unbedingt die Antwort, aber wenn mich jemand auf Literatur oder Beispiele hinweisen könnte. Ich würde es gerne herausfinden.

Wenn ich das Skript ausführe, erhalte ich eine Fehlermeldung:

Syntaxfehler in der Nähe eines unerwarteten Tokens fi

Ich habe festgestellt, dass mein Problem in meiner ifAussage liegt, indem ich meine ifAussagen kommentierte und hinzufügte, in echo "$NAME"der die Namen angezeigt werden /etc/.

Wenn ich Änderungen vornehme, die #aus ifund entferne fiund zu hinzufüge #, wc -c "$NAME"wird der oben aufgeführte Syntaxfehler angezeigt. Ich habe ;zwischenzeitlich hinzugefügt ]. Ich bin auch thenohne Auflösung in die nächste Zeile gewechselt.

#!/bin/bash
for NAME in /etc/*
do

     if [ -r "$NAME" -af "$NAME" ] then
          wc -c "$NAME"
     fi
done
Christina A Guzman
quelle
9
Wenn Sie einen Shell-Syntaxfehler haben, ist es ein guter erster Schritt, Ihren Code auszuschneiden und in shellcheck.net einzufügen und die identifizierten Fehler zu korrigieren. Wenn Sie Probleme beim Verstehen der Nachrichten haben, kommen Sie hierher und fragen Sie.
John1024
2
Was -afsoll das denn machen
Ilkkachu
Vielen Dank für diese Site @ John1024 es war sehr nützlich, ich habe es für zukünftige Referenz vorgemerkt.
Christina A Guzman
1
@ChristinaAGuzman In einem solchen Fall -aist überflüssig, da die Bedingung bereits enthalten ist -f. --- Auf jeden Fall müssen mehrere Bedingungen innerhalb [ ](dieser Befehl ist auch verfügbar als test) mit logischen Operatoren wie -a(und) oder -o(oder) verknüpft werden. Wie in der Antwort unten vorgeschlagen, ist es jedoch besser, mehrere [ ]( test) Befehle und Verknüpfungen zu verwenden sie mit Shell-Operatoren wie &&oder ||.
Pabouk
2
Christina, wie @ John1024 betont, zeigt shellcheck.net sehr deutlich einige Syntax- oder noch tiefere Fehler (wie bei C-Code). Ich empfehle auch ein Muss: mywiki.wooledge.org/BashPitfalls (mindestens einmal lesen!) Und mywiki.wooledge.org/BashFAQ und mywiki.wooledge.org/BashGuide sind ebenfalls gut zu lesen.
Olivier Dulac

Antworten:

46

Schlüsselwörter wie if, then, else, fi, for, caseund so weiter Bedarf an einem Ort zu sein , wo die Schale einen Befehlsnamen erwartet. Ansonsten werden sie wie gewöhnliche Wörter behandelt. Beispielsweise,

echo if

Es wird nur gedruckt if, es wird keine bedingte Anweisung gestartet.

Also in der Leitung

if [ -r "$NAME" -af "$NAME" ] then

Das Wort thenist ein Argument des Befehls [(über das es sich beschweren würde, wenn es jemals ausgeführt würde). Die Shell sucht weiter nach thenund findet eine fiIn-Command-Position. Da es einen gibt if, der noch auf der Suche ist then, der fiunerwartet ist, liegt ein Syntaxfehler vor.

Sie müssen einen Befehlsabschluss setzen, thendamit er als Schlüsselwort erkannt wird. Das gebräuchlichste Befehlsende ist ein Zeilenumbruch. Früher wird jedoch thenhäufig ein Semikolon verwendet (das genau die gleiche Bedeutung hat wie ein Zeilenumbruch).

if [ -r "$NAME" -af "$NAME" ]; then

oder

if [ -r "$NAME" -af "$NAME" ]
then

Sobald Sie dieses Problem behoben haben, wird der Befehl einen weiteren Fehler enthalten, [da er nicht verstanden wird -af. Sie meinten vermutlich

if [ -r "$NAME" -a -f "$NAME" ]; then

Obwohl die Testbefehle wie Optionen aussehen, können Sie sie nicht so bündeln. Sie sind Operatoren des [Befehls und müssen jeweils ein separates Wort sein (as do [und ]).

Übrigens, obwohl es [ -r "$NAME" -a -f "$NAME" ]funktioniert, empfehle ich das Schreiben

[ -r "$NAME" ] && [ -f "$NAME" ]

oder

[[ -r $NAME && -f $NAME ]]

Es ist am besten, die [ … ]Bedingungen einfach zu halten , da der [Befehl Operatoren nicht leicht vom Operanden unterscheiden kann. Wenn es $NAMEwie ein Operator aussieht und an einer Position angezeigt wird, an der der Operator gültig ist, kann es als Operator analysiert werden. Dies ist in den einfachen Fällen, die in dieser Antwort angegeben sind, nicht der Fall, aber komplexere Fälle können ein Risiko darstellen. Wenn Sie dies mit separaten Aufrufen an [die logischen Operatoren der Shell schreiben und diese verwenden, wird dieses Problem vermieden.

Die zweite Syntax verwendet das [[ … ]]in bash (und ksh und zsh, aber nicht plain sh) vorhandene bedingte Konstrukt. Dieses Konstrukt wird eine spezielle Syntax, während [wie jeder andere Befehl analysiert wird, so dass Sie Dinge wie können &&innen und Sie nicht zu zitieren Variablen außer in Argumente für einige String - Operatoren (müssen =, ==, !=, =~) (siehe Wenn doppelt unter Angabe erforderlich ? für Details).

Gilles 'SO - hör auf böse zu sein'
quelle
Beachten Sie, dass dies if [[ 1 ]] then [[ 2 ]] fiin ksh, pdksh und zsh funktioniert. if(:)then(:)fifunktioniert in allen Schalen.
Stéphane Chazelas
12

Sehen Sie, was sich wie folgt geändert hat

if [-r "$ NAME" -a -f "$ NAME"] ; dann
# ^^^^^^
     wc -c "$ NAME"
fi

Wenn Sie alle Befehle im if-Block entfernen möchten, müssen Sie mindestens einen Doppelpunkt hinzufügen, z

if [ -r "$NAME" -a -f "$NAME" ]; then
    :
fi

oder einzeilige Version

if [ -r "$NAME" -a -f "$NAME" ]; then :; fi

Bruce
quelle
2

Andere haben bereits darauf hingewiesen, aber wenn Sie nach einer offiziellen Referenz suchen, dann ist RTM

if list; dann Liste; [Elif-Liste; dann Liste; ] ... [else list;] fi

Die if-Liste wird ausgeführt. Wenn der Beendigungsstatus Null ist, wird die Then-Liste ausgeführt. Andernfalls wird jede elif-Liste der Reihe nach ausgeführt, und wenn ihr Beendigungsstatus Null ist, wird die entsprechende then-Liste ausgeführt und der Befehl abgeschlossen. Andernfalls wird die else-Liste ausgeführt, falls vorhanden. Der Beendigungsstatus ist der Beendigungsstatus des zuletzt ausgeführten Befehls oder Null, wenn keine Bedingung als wahr getestet wurde.

Sie vermissen die ;

Und die Syntax für listist in beschriebenman test

Kashyap
quelle