Script Shell - erreur de syntaxe près du jeton inattendu "else"

15

Avec le script shell suivant, pourquoi j'obtiens des erreurs

syntax error near unexpected token `else'

Script Shell

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
Jacob
la source
vous souhaiterez peut-être modifier la ligne "copier à partir de ...." car elle peut afficher actuellement quelque chose que vous ne souhaitez pas afficher. (Cependant, j'espère que ceux-ci sont déjà des infos modifiées, car ils seraient vraiment mal sécurisés)
Olivier Dulac
1
@OlivierDulac Si vous faites référence au nom d'utilisateur et au mot de passe sur cette ligne, ceux-ci sont connus de tous les utilisateurs de la base de données Oracle. Il est courant et bien connu depuis le début de la base de données Oracle.
Jåcob
@OlivierDulac Vous êtes les bienvenus, quelques informations sur ce dba-oracle.com/t_scott_tiger.htm
Jåcob

Réponses:

25

Vous devez mettre fin à la condition ifsuivante:

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

ou comme ça:

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

Remarque: vous devez également mettre des espaces après [et avant ].

La raison du ;saut de ligne ou est que la partie condition de l' ifinstruction n'est qu'une commande. Toute commande de n'importe quelle longueur pour être précis. Le shell exécute cette commande, examine l'état de sortie de la commande, puis décide d'exécuter la thenpièce ou la elsepièce.

Comme la commande peut être de n'importe quelle longueur, il doit y avoir un marqueur pour marquer la fin de la partie condition. C'est le ;ou la nouvelle ligne, suivi de then.

La raison des espaces après [est parce que [c'est une commande. Habituellement, une coquille intégrée. Le shell exécute la commande [avec le reste comme paramètres, y compris le ]dernier paramètre obligatoire. Si vous ne mettez pas d'espace après [le shell, il tentera de s'exécuter en [whatevertant que commande et échouera.

La raison de l'espace avant le ]est similaire. Sinon, il ne sera pas reconnu comme un paramètre à part entière.

lesmana
la source
C'était test.sh: line 6: [: missing
parfait
@lesmana. Un bon moyen de fournir d'abord une mauvaise réponse, puis de continuer à modifier avant que quelqu'un d'autre ne donne la bonne réponse. Veuillez essayer de fournir la bonne réponse la première fois.
Valentin Bajrami
1
Je ne considère pas ma première réponse comme erronée. En fait, c'était "parfait". Cela n'a tout simplement pas résolu tous les problèmes de la question.
lesmana
if est la syntaxe, ce n'est pas une commande ordinaire. C'est un mot réservé. Contrairement à de nombreux autres langages de programmation, le shell ne reconnaît pas les mots réservés partout, uniquement lorsqu'ils sont le premier mot d'une commande (avec quelques subtilités).
Gilles 'SO- arrête d'être méchant'
Merci pour la clarification. Je suis conscient que ifc'est la syntaxe. J'essayais de communiquer que la partie condition de la ifn'est pas limitée à une certaine forme par la syntaxe. J'ai édité le texte. J'espère que c'est plus clair maintenant.
lesmana
5

Vous pouvez facilement vérifier vos scripts shell à l'aide de ShellCheck en ligne (également disponible en tant qu'outil autonome).

Dans ce cas, il indiquera que l'instruction if a besoin d'espaces, après [et avant ], et que vous avez besoin d'un ;(ou d'un retour à la ligne) avant le thensur la même ligne.

Lorsque vous aurez corrigé cela, il vous dira qu'il USER_NAMEest utilisé sans être initialisé à quoi que ce soit. En effet, vous avez également une user_namevariable (le cas est important). Il en va de même pour PASSet pass.

Il vous indique également d'utiliser read -rpour arrêter la readmanipulation \(peut être important pour les mots de passe, par exemple), et que vous devez doubler les variables lors de l'appel sqlpluspour empêcher le shell de faire accidentellement le remplacement de nom de fichier et le fractionnement de mot (encore une fois, cela est important si le mot de passe, par exemple, contient des caractères de remplacement de fichier comme *, ou des espaces).

Le retrait du code le rendra également plus lisible:

#!/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

Ici, j'ai également permis d'utiliser des mots de passe avec des caractères d'espace de début ou de fin en définissant temporairement IFSune chaîne vide pour la lecture du mot de passe read.

La logique a également été modifiée pour renflouer si $ORACLE_SID/ $sidest Test. Cela évite d'avoir la partie opérationnelle principale du script dans une ifbranche.

Kusalananda
la source
Notez que cela if ([ x = x ]) then (echo yes) fifonctionne également.
Stéphane Chazelas
@ StéphaneChazelas Ah, oui. Et cela peut être intéressant du point de vue d'un programme générant du code shell, mais ce n'est pas comme ça qu'on écrit habituellement des ifinstructions avec [ ... ]... :-)
Kusalananda
2

Lors de l'écriture, shvous voudriez

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

Lors de l'écriture bash

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

Attention aux espaces s'il vous plaît. Il doit y avoir un espace entre le [[premier opérateur.

Valentin Bajrami
la source