J'apprends les structures de prise de décision et je suis tombé sur ces codes:
if [ -f ./myfile ]
then
cat ./myfile
else
cat /home/user/myfile
fi
[ -f ./myfile ] &&
cat ./myfile ||
cat /home/user/myfile
Les deux se comportent de la même façon. Y a-t-il des avantages à utiliser dans un sens ou dans l'autre?
shell-script
syntax
control-flow
Subhaa Chandar
la source
la source
Réponses:
Non, les constructions
if A; then B; else C; fi
et neA && B || C
sont pas équivalentes .Avec
if A; then B; else C; fi
, la commandeA
est toujours évaluée et exécutée (au moins une tentative d'exécution est effectuée), puis la commandeB
ou la commandeC
sont évaluées et exécutées.Avec
A && B || C
, c'est la même chose pour les commandesA
etB
mais différent pourC
: la commandeC
est évaluée et exécutée en cas d'A
échec ou d'B
échec.Dans votre exemple, supposez que vous
chmod u-r ./myfile
, malgré les[ -f ./myfile ]
succès, vouscat /home/user/myfile
Mon conseil: utilisez
A && B
ouA || B
tout ce que vous voulez, cela reste facile à lire et à comprendre et il n'y a pas de piège. Mais si vous voulez dire si ... alors ... sinon ... alors utilisezif A; then B; else C; fi
.la source
La plupart des gens trouvent plus facile de comprendre le
if
...then
...else
...fi
formulaire.Pour le
a && b || c
, vous devez être sûr que celab
renvoie vrai. Ceci est une cause de bugs subtils et est une bonne raison d'éviter ce style. Si b ne retourne pas vrai, ce ne sont pas les mêmes.Pour les tests et actions très courts qui n'ont pas de clause else, la longueur raccourcie est intéressante, par exemple
&&
et||
sontshort circuiting operators
, dès que le résultat est connu, d'autres tests inutiles sont ignorés.a && b || c
est groupé comme(a && b) || c
. Le premiera
est exécuté. S'ilfails
est défini comme ne renvoyant pas un état de sortie de 0, alors le groupe(a && b)
est connufail
etb
n'a pas besoin d'être exécuté. Le||
ne connaît pas le résultat de l'expression et doit donc s'exécuterc
. Sia
réussit (renvoie zéro), l'&&
opérateur ne connaît pas encore le résultat dea && b
donc doit s'exécuterb
pour le découvrir. Sib
réussit,a && b
réussit et||
sait que le résultat global est un succès, il n'est donc pas nécessaire de l'exécuterc
. Sib
échoue alors||
ne connaît toujours pas la valeur de l'expression, il doit donc s'exécuterc
.la source
L'opérateur && exécute la commande suivante si la commande précédente a réussi, (code de sortie retourné ($?) 0 = logique vrai).
Dans la forme
A && B || C
, la commande (ou la condition) A est évaluée et si A renvoie vrai (succès, code de sortie 0) alors la commande B est exécutée. Si A échoue (retourne donc faux - code de sortie autre que 0) et / ou B échoue (retourne faux ), alors la commande C sera exécutée.L'
&&
opérateur est également utilisé comme ET dans les vérifications de condition et l'opérateur||
fonctionne comme OU dans les vérifications de condition.Selon ce que vous voulez faire avec votre script, le formulaire
A && B || C
peut être utilisé pour des vérifications de conditions comme votre exemple ou peut être utilisé pour chaîner des commandes et garantir une série de commandes à exécuter si les commandes précédentes avaient un code de sortie 0 réussi .Voilà pourquoi il est fréquent de voir des commandes telles que :
do_something && do_something_else_that_depended_on_something
.Exemples:
apt-get update && apt-get upgrade
si la mise à jour échoue, la mise à niveau n'est pas exécutée (est logique dans le monde réel ...).mkdir test && echo "Something" > test/file
La partie
echo "Something"
ne sera exécutée qu'en cas demkdir test
succès et l'opération a renvoyé le code de sortie 0 ../configure --prefix=/usr && make && sudo make install
Habituellement trouvé lors de la compilation de travaux pour enchaîner les commandes dépendantes nécessaires.
Si vous essayez d'implémenter les "chaînes" ci-dessus avec if - alors - sinon vous aurez besoin de beaucoup plus de commandes et de vérifications (et donc plus de code à écrire - plus de choses à se tromper) pour une tâche simple.
Gardez également à l'esprit que les commandes chaînées avec && et || sont lus par shell de gauche à droite. Vous devrez peut-être regrouper les commandes et les vérifications de condition avec des crochets pour dépendre de la prochaine étape de la sortie réussie de certaines commandes précédentes. Par exemple, voyez ceci:
Ou un exemple réel:
Gardez à l'esprit que certaines commandes renvoient des codes de sortie différents en fonction du processus exécuté ou retournent des codes différents en fonction de leurs actions (par exemple, la commande GNU
diff
renvoie 1 si deux fichiers diffèrent et 0 si ce n'est pas le cas). Ces commandes doivent être traitées avec soin dans && et || .Aussi juste pour avoir tout le puzzle ensemble, gardez à l'esprit la concaténation des commandes à l'aide de l'
;
opérateur. Avec un formatA;B;C
toutes les commandes seront exécutées en série quel que soit le code de sortie de la commandeA
etB
.la source
Une grande partie de la confusion à ce sujet peut être due à la documentation bash appelant ces listes AND et OR . Bien qu'ils soient logiquement similaires à
&&
et||
trouvés entre crochets, ils fonctionnent différemment.Quelques exemples peuvent illustrer ce mieux ...
Si
cmda
quitte vrai,cmdb
est exécuté.Si
cmda
exit false,cmdb
n'est PAS exécuté, mais l'cmdc
est.Comment les
cmda
sorties sont ignorées.Si
cmdb
quitte vrai,cmdc
est exécuté.Si
cmdb
exit false,cmdc
n'est PAS exécuté et l'cmdd
est.Si
cmda
quitte vrai,cmdb
est exécuté, suivi decmdc
.Si
cmda
exit false,cmdb
n'est PAS exécuté mais l'cmdc
est.Hein? Pourquoi est
cmdc
exécuté?Parce que pour l'interprète, un point-virgule (
;
) et une nouvelle ligne signifient exactement la même chose. Bash voit cette ligne de code comme ...Pour réaliser ce qui est attendu, nous devons
cmdb; cmdc
mettre entre accolades des accolades pour en faire une commande composée (commande de groupe) . Le point-virgule de fin supplémentaire n'est qu'une exigence de la{ ...; }
syntaxe. Nous obtenons donc ...cmda && { cmdb; cmdc; }
Si
cmda
quitte vrai,cmdb
est exécuté, suivi decmdc
.Si
cmda
exit false, ni l'uncmdb
ni l'autrecmdc
n'est exécuté.L'exécution se poursuit avec la ligne suivante.
Usage
Les listes de commandes conditionnelles sont très utiles pour revenir le plus rapidement possible à partir des fonctions et éviter ainsi d'interpréter et d'exécuter beaucoup de code inutile. Les retours de fonctions multiples signifient cependant que l'on doit être obsédé par le fait de garder les fonctions courtes afin qu'il soit plus facile de s'assurer que toutes les conditions possibles sont couvertes.
Voici un exemple de code en cours d'exécution ...
la source