2 votes

Une condition avec plusieurs commandes

Est-il possible de faire quelque chose comme ça?

if
rsync $folder/coopshop/prod $folder2/coopshop
rsync $folder/coopweb/prod $folder2/coopweb
rsync $folder/unihobbyshop/shop $folder2/unihobbyshop
rsync $folder/unnihobbyweb/web $folder2/unihobbyweb
then
  echo "OK! rsync done!"
else
  echo "Error! rsync crashed!"
fi

Je sais qu'il y a une possibilité de le faire avec le caractère \ à la fin de la ligne, mais ce n'est pas tout à fait une solution élégante. Y a-t-il un meilleur moyen de faire cela?

5voto

Eliah Kagan Points 111731

Considérez set -e.

Si ceci est dans un script, alors vous voudrez probablement supprimer le if...then entièrement et simplement mettre set -e en haut du script. Cela fait en sorte que le script s'arrête immédiatement si une commande échoue. Lorsque l'une de ces commandes rsync échouent, elles afficheront des messages d'erreur expliquant l'échec, il est donc probable que vous n'ayez pas besoin d'écrire votre propre message du tout.

Si vous souhaitez afficher les commandes qui sont exécutées avant de les lancer, utilisez set -x. Vous pouvez combiner les deux en écrivant set -ex.

Avec &&, vous n'avez pas besoin de \.

Si vous décidez d'écrire quelque chose dans le sens de ce que vous avez montré, alors comme le dit Ronny Blomme vous pouvez séparer les commandes avec &&. Notez que vous n'avez pas besoin d'exécuter les commandes dans des sous-shell, c'est-à-dire, vous n'avez pas besoin de les enfermer dans des parenthèses.

Si vous écrivez un opérateur && à la fin d'une ligne, alors vous n'avez pas besoin d'écrire \ pour spécifier la continuation de la ligne. Une commande ne peut pas se terminer par && (logique ET) ou || (logique OU) donc le shell continuera l'analyse sur la ligne suivante.

if
    rsync "$folder/coopshop/prod" "$folder2/coopshop" &&
    rsync "$folder/coopweb/prod" "$folder2/coopweb" &&
    rsync "$folder/unihobbyshop/shop" "$folder2/unihobbyshop" &&
    rsync "$folder/unnihobbyweb/web" "$folder2/unihobbyweb"
then
    echo 'OK! Les commandes rsync se sont terminées avec succès!'
else
    echo 'Erreur! une commande rsync a échoué!'
fi

Vous n'êtes pas obligé de mettre && à la fin d'une ligne. Vous pouvez écrire plusieurs commandes sur la même ligne séparées par && si vous le souhaitez.

Notez que la commande finale testée ne se termine pas par && car && sépare les commandes. Si une commande échoue, les autres ne s'exécuteront pas.

Exécuter toutes les commandes même si certaines échouent

Vous pouvez également vouloir exécuter toutes les commandes rsync même si certaines échouent, puis tester si l'une d'entre elles a échoué et agir en conséquence. Pour cela, vous pouvez "piéger" ERR. Ce n'est pas un signal réel, mais la spécification de signal ERR dans bash capture les commandes qui échouent pour n'importe quelle raison, y compris un crash (et y compris SIGINT). Voir la réponse de pLumo (mais omettez set -e pour continuer) et ce post de William Pursell; pour plus d'informations générales, voir la sortie de help trap.

La façon dont j'aime le faire (avec des commandes comme les vôtres insérées) est la suivante :

failed=
trap 'failed=yes' ERR

rsync "$folder/coopshop/prod" "$folder2/coopshop"
rsync "$folder/coopweb/prod" "$folder2/coopweb"
rsync "$folder/unihobbyshop/shop" "$folder2/unihobbyshop"
rsync "$folder/unnihobbyweb/web" "$folder2/unihobbyweb"

if [ -z "$failed" ]; then
    echo 'OK! Les commandes rsync se sont terminées avec succès!'
else
    echo "Erreur! certaines commandes rsync ont échoué!"
fi

À propos des autres modifications que j'ai apportées... et ce que if _command_ teste vraiment.

Vos arguments pour rsync utilisent l'expansion des paramètres donc j'ai pris la liberté de les mettre entre guillemets doubles. Sinon, la séparation des mots et le globbing seront effectués. De par le contexte, il semble que vous ne vouliez pas ces expansions supplémentaires. (Généralement, vous ne le voulez pas.)

Notez que, contrairement au message imprimé par votre script, vous ne testez pas réellement si une commande rsync a planté. Vous testez en réalité si une commande rsync a échoué. Un plantage est une fin anormale du programme, où un processus est terminé par un signal, généralement en raison d'un bug ou d'une condition qui ne peut pas être traitée raisonnablement. C'est bien plus rare qu'une fin normale du programme, qui peut elle-même se produire avec un statut de sortie indiquant un succès (zéro) ou un échec (un autre nombre). Si rsync plante, le code ci-dessus le détectera également. Mais la plupart du temps, il attrape en fait les fins normales du programme avec un statut de sortie indiquant un échec.

3voto

pLumo Points 23269

Pour un script comme le vôtre, je n'utiliserais pas if/else, mais j'activerais la sortie en cas d'erreur (set -e) et le piégeage.

Quelque chose comme ceci :

#!/bin/bash

set -euo pipefail
trap 'echo "Erreur ! rsync a planté!"' ERR INT

rsync $folder/coopshop/prod $folder2/coopshop
rsync $folder/coopweb/prod $folder2/coopweb
rsync $folder/unihobbyshop/shop $folder2/unihobbyshop
rsync $folder/unnihobbyweb/web $folder2/unihobbyweb

echo "OK ! rsync terminé !"

1voto

Ronny Blomme Points 51

Essayez cette syntaxe:

#!/bin/bash
mkdir dir1 dir2
echo "test1" > dir1/file1
echo "test2" > dir1/file2

if (rsync dir1/file1 dir2) && (rsync dir1/file2 dir2) 
then
  echo "OK! rsync terminé!"
else
  echo "Erreur! rsync a planté!"
fi

-1voto

Shaggydog Points 1268

J'ai essayé ceci.

commands=$(
mkdir 1
mkdir 2
)

if($commands); then
  echo 'Ok.'
else
  echo 'False.'
fi

Ça fonctionne. Le problème survient lorsque j'ajoute par exemple ls -la aux commandes, ça échoue avec ceci.

./test: line 7: total: command not found

Je ne sais pas pourquoi.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X