Shell Script - Syntaxfehler in der Nähe des unerwarteten Tokens "else"

15

Warum erhalte ich mit dem folgenden Shell-Skript Fehler?

syntax error near unexpected token `else'

Shell-Skript

echo "please enter username"
read user_name
echo "please enter password"
read -s pass
echo ${ORACLE_SID}
SID=${ORACLE_SID}
if ["${ORACLE_SID}" != 'Test'] then
sqlplus -s -l $USER_NAME/$PASS@$SID <<EOF
copy from scott/tiger@orcl insert EMP using select * from EMP
exit
EOF
else
echo "Cannot copy"
fi
Jakob
quelle
Möglicherweise möchten Sie die Zeile "Kopieren von ..." bearbeiten, da gerade etwas angezeigt wird, das Sie nicht anzeigen möchten. (Ich hoffe jedoch, dass dies bereits geänderte Informationen sind, da dies in Bezug auf die Sicherheit sehr unzureichend wäre.)
Olivier Dulac
1
@OlivierDulac Wenn Sie in dieser Zeile auf Benutzername und Kennwort verweisen, sind diese allen Benutzern der Oracle-Datenbank bekannt. Es ist seit Beginn der Oracle-Datenbank weit verbreitet und bekannt.
Jåcob
@OlivierDulac Gern
geschehen

Antworten:

25

Sie müssen die Bedingung ifwie folgt kündigen :

if [ "${ORACLE_SID}" != 'Test' ]; then

oder so:

if [ "${ORACLE_SID}" != 'Test' ]
then

Hinweis: Sie müssen auch Leerzeichen nach [und vor setzen ].

Der Grund für den ;Zeilenumbruch ist, dass der Bedingungsteil der ifAnweisung nur ein Befehl ist. Jeder Befehl von beliebiger Länge, um genau zu sein. Die Shell führt diesen Befehl aus, überprüft den Beendigungsstatus des Befehls und entscheidet dann, ob das thenTeil oder das elseTeil ausgeführt werden soll.

Da der Befehl beliebig lang sein kann, muss eine Markierung vorhanden sein, um das Ende des Bedingungsteils zu markieren. Das ist die ;oder die neue Zeile, gefolgt von then.

Der Grund für die Räume nach [, weil [ein Befehl ist. In der Regel ein eingebautes der Shell. Die Shell führt den Befehl [mit dem Rest als Parameter aus, einschließlich des ]obligatorischen letzten Parameters. Wenn Sie nach [der Shell kein Leerzeichen setzen, versucht die Shell, [whateverden Befehl auszuführen, und schlägt fehl.

Der Grund für den Platz vor dem ]ist ähnlich. Denn sonst wird es nicht als eigener Parameter erkannt.

lesmana
quelle
Das war test.sh: line 6: [: missing
genau richtig
@lesmana. Eine gute Möglichkeit, zuerst eine falsche Antwort einzugeben und dann weiter zu bearbeiten, bevor eine andere Person die richtige Antwort eingibt. Bitte versuchen Sie beim ersten Mal, die richtige Antwort zu geben.
Valentin Bajrami
1
Ich halte meine erste Antwort nicht für falsch. Tatsächlich war es "genau richtig". Es hat einfach nicht alle Probleme in der Frage gelöst .
Lesmana
if ist Syntax, es ist kein gewöhnlicher Befehl. Es ist ein reserviertes Wort. Im Gegensatz zu vielen anderen Programmiersprachen erkennt die Shell reservierte Wörter nicht überall, nur wenn sie das erste Wort eines Befehls sind (mit ein paar Feinheiten).
Gilles 'SO - hör auf böse zu sein'
Danke für die Klarstellung. Mir ist bewusst, dass ifdas Syntax ist. Ich habe versucht zu kommunizieren, dass der Bedingungsteil von ifnicht durch Syntax auf eine bestimmte Form beschränkt ist. Ich habe den Text bearbeitet. Ich hoffe es ist jetzt klarer.
Lesmana
5

Sie können Ihre Shell-Skripte problemlos mit ShellCheck online überprüfen (auch als eigenständiges Tool verfügbar).

In diesem Fall wird darauf hingewiesen, dass die if-Anweisung nach [und vor Leerzeichen benötigt ]und dass Sie ;vor thenderselben Zeile ein (oder ein neues) Zeichen benötigen .

Wenn Sie dies behoben haben, wird Ihnen mitgeteilt, dass USER_NAMEdie Datei verwendet wird, ohne dass eine Initialisierung erforderlich ist. Dies liegt daran, dass Sie auch eine user_nameVariable haben (case matters). Gleiches gilt für PASSund pass.

Es sagt Ihnen auch, dass Sie verwenden sollen read -r, um das readZerfleischen zu unterbinden \(was zum Beispiel für Kennwörter wichtig sein könnte) und dass Sie die Variablen beim Aufrufen sqlplusin doppelte Anführungszeichen setzen sollten, um zu verhindern, dass die Shell versehentlich Dateinamen verschiebt und Wörter aufteilt (dies ist wiederum wichtig, wenn Das Passwort enthält zum Beispiel Zeichen wie "Datei" *oder Leerzeichen.

Durch Einrücken des Codes wird er auch lesbarer:

#!/bin/bash

read -r -p 'please enter username: ' user_name
IFS= read -rs -p 'please enter password: ' pass

printf 'ORACLE_SID = %s\n' "$ORACLE_SID"
sid=$ORACLE_SID

if [ "$sid" = 'Test' ]; then
    echo 'Cannot copy' >&2
    exit 1
fi

sqlplus -s -l "$user_name/$pass@$sid" <<'SQL_END'
copy from scott/tiger@orcl insert EMP using select * from EMP
exit
SQL_END

Hier habe ich es auch möglich gemacht, Passwörter mit führenden oder nachfolgenden Leerzeichen zu verwenden, indem vorübergehend IFSeine leere Zeichenfolge für das Lesen des Passworts festgelegt wurde read.

Die Logik wurde auch geändert, um zu retten, wenn $ORACLE_SID/ $sidist Test. Dadurch wird vermieden, dass sich der Hauptbetriebsteil des Skripts in einer ifVerzweigung befindet.

Kusalananda
quelle
Beachten Sie, dass if ([ x = x ]) then (echo yes) fiauch funktioniert.
Stéphane Chazelas
@ StéphaneChazelas Ah ja. Und das mag aus der Sicht eines Programms, das Shell-Code generiert, interessant sein, aber so schreibt man normalerweise keine ifAnweisungen mit [ ... ]... :-)
Kusalananda
2

Wenn shSie schreiben , möchten Sie

if [ "$ORACLE_SID" != "Test" ]
then
  ...
fi

Beim Schreiben bash

if [[ "$ORACLE_SID" != "Test" ]]
then
  ...
fi

Bitte beachten Sie die Leerzeichen. Zwischen [[und dem ersten Operator muss ein Leerzeichen stehen .

Valentin Bajrami
quelle