web-dev-qa-db-fra.com

Erreur de syntaxe Bash lorsque "else" suit une clause "then" vide

Pourquoi le script suivant ne s'exécuterait-il pas, mais donnerait une erreur de syntaxe de else:

LOGS3_DIR=~/logs
if [ -d "$LOGS3_DIR" ]; then
 cd
 cd "$LOGS3_DIR"
 echo "$LOGS3_DIR"
 for filename in `find "." -mtime 1 -type f`
  do
  if lsof "$filename" > /dev/null
  then
    # file is open
  else
    echo "deleting $filename"
    rm "$filename"
  fi
 done
fi
38
Novice User

N'utilisez pas de substitution de commande sur la sortie de find . Ici, tout peut être fait avec find:

find . -mtime 1 -type f ! -exec lsof -t {} \; -exec rm -f {} \; > /dev/null

Avec quelques implémentations find (y compris FreeBSD find d'où il vient et GNU find), vous pouvez utiliser -delete au lieu de -exec rm....

La raison pour laquelle vous obtenez une erreur est qu'il n'y a pas de commande entre then et else et certains shells (à commencer par le Bourne Shell d'où vient cette syntaxe) en nécessitent au moins un (et un commentaire n'est pas une commande). Notez que c'est complètement arbitraire et il n'y a aucune raison pour que ces obus fassent cela. yash et zsh n'ont pas cette limitation (if false; then else echo x; fi et même if false; then else fi fonctionnent bien avec eux).

Comme d'autres l'ont dit, vous pouvez utiliser une commande noop comme : (Ou for nothing in; do nothing; done) Ou inverser la logique avec le mot clé ! (Disponible dans les shells POSIX, mais pas le Bourne Shell (vous constaterez que l'utilisation de : Pour cela était courante dans ce Shell)). mksh et yash arrivent à supporter if false; then () else echo x; fi (je ne compterais pas dessus car cela pourrait changer dans les futures versions).

Une autre approche consiste à:

lsof... || {
  cmd1
  cmd2
}

bien qu'une différence soit le statut de sortie global qui sera celui de lsof si lsof échoue.

23

Il semble que vous souhaitiez faire un no-op si le fichier est ouvert, vous devez donc ajouter un :, qui est une commande nulle dans bash:

if lsof "$filename" > /dev/null; then
  # file is open
  :
else
  printf 'deleting %s\n' "$filename"
  rm -- "$filename"
fi

Si vous n'utilisez pas :, bash ne peut pas analyser votre code et affichera une erreur comme bash: syntax error near unexpected token 'else'.

95
cuonglm

Une autre alternative: inversez votre logique.

if ! lsof "$filename" >/dev/null;then
    echo "deleting $filename"
    rm "$filename"
fi
26
Joseph R.

TL; DR

Aucune des autres réponses ne répond réellement à votre question initiale de savoir pourquoi la commande donne une erreur de syntaxe. Cela est dû à une commande manquante entre puis et else .

Une commande manquante

Votre code d'origine ressemble à ceci:

if lsof "$filename" > /dev/null
then
  # file is open
else
  echo "deleting $filename"
  rm "$filename"
fi

Le problème est que vous avez un commentaire entre puis et else , mais le commentaire n'est pas traité comme une commande. En bref, vous pouvez réécrire le problème que vous avez (structurellement parlant) comme suit:

$ if true; then else echo; fi
bash: syntax error near unexpected token `else'

Corrigez votre syntaxe avec un Bourne Builtin

Vous pouvez résoudre ce problème en plaçant les commandes réelles avant autrement , mais un commentaire en lui-même ne fera pas l'affaire. La section if-then ne peut pas être vide; si vous voulez un espace réservé, vous pouvez utiliser le colon intégré . Par exemple:

$ if true; then :; else echo; fi

Placer simplement : dans la section entre puis et sinon corrigera l'erreur de syntaxe vous vivez.

17
CodeGnome