Bash est un langage dont la coolitude ne cesse de me surprendre. J'en apprends littéralement tous les jours.
Il existe des tas de sites où vous trouverez des tas d'astuces sur l'utilisation avancée du Bourne-Again SHell. Par exemple sur l'utilisation des redirections, des substitutions de processus, les tableaux associatifs, les documents-en-place (here-document), chaines-en-place (here-string), les tuyaux nommés, les nombreux types d'expansion, etc, etc.
Mais récemment y'a une astuce toute bête que je n'ai jamais vraiment lu nul part sur une structure des plus banales: le if then elif else fi.
Il faut savoir qu'après un if ou un elif, on n'est pas obligé de ne mettre qu'une commande. On peut mettre une liste de commandes.
Ainsi, une commande telle que:
echo "I am going to run foo"
if foo
then echo "I did run foo"
fi
peut être remplacée par:
if
echo "I am going to run foo"
foo
then echo "I did run foo"
fi
« Oui, et alors ? », me direz-vous. Et bien, le truc c'est que grâce à ça on n'a pas à imbriquer des if.
Ainsi:
echo "I am going to run foo"
if foo
then
echo "I did run foo"
echo "now I am going to run bar"
if bar
then "I did run bar"
fi
fi
peut être écrit dans une seule structure if:
if
echo "I am going to run foo"
! foo
then echo "oops"
elif
echo "I did run foo"
echo "now I am going to run bar"
bar
then echo "I did run bar"
fi
Et là on comprends que cette idée est très utile pour gérer les erreurs:
if ! foo
then error "something went wrong trying to run foo"
elif
echo "I did run foo"
echo "Now I'm going to run bar"
! bar
then error "something went wrong trying to run bar"
elif
echo "I did run bar"
echo "Now I'm going to run jiz"
! jiz
then error "something went wrong trying to run jiz"
else echo "I could go on like this forever"
fi
AMHA ce style de programmation présente parmi ses avantages, celui d'inciter le programmeur à développer du code robuste, car il doit penser à gérer les erreurs d'abords, pour chaque étape du programme.
En fait il me semble que presque sans exagérer on peut dire qu'on devrait pouvoir écrire n'importe quel programme bash dans une seule grande structure if then elif ... else fi
# .
Posté par Troy McClure (site web personnel) . Évalué à 10.
c'est pas plus simple de faire juste
foo || error "oulala"
bar || error "oulalalala"
?
[^] # Re: .
Posté par grondilu . Évalué à 2.
Ben ici le "error" n'est qu'un exemple mais dans le cas général ça peut être n'importe quel liste de commande. Et surtout il n'est pas sensé quitter le programme, mais uniquement la boucle if.
Donc dans ton exemple il faudrait un moyen de spécifier qu'après l'exécution de l'error qui suit l'échec de fou, le programme continue après la ligne bar. Bref c'est pas du tout le même programme.
[^] # Re: .
Posté par Michaël (site web personnel) . Évalué à 2.
Ton programme est donc beaucoup trop long! :)
Ensuite tu peux te contenter d'un
return
dans le terme de droite de||
si tu ne veux pas quitter le programme ou enfermer ta procédure susceptible de contenir des erreurs dans un sous-shell (grâce à(
et)
). Si on programme un outil simple on peut se contenter de exit et éventuellement enregistrer un callback pour le pseudo-signal EXIT.# Lisibilité
Posté par Olorim . Évalué à 9.
Intéressant, mais cela ne nuit pas à la lisibilité? Sur un script d'une dizaine de ligne ok, mais sur de gros script?
[^] # Re: Lisibilité
Posté par grondilu . Évalué à 2.
Au contraire, depuis que je programme comme ça, je trouve mon code beaucoup plus lisible.
[^] # Re: Lisibilité
Posté par Olorim . Évalué à 5.
Hahem...comment dire? j'aimerai pas avoir à maintenir tes scripts...
Le prend pas mal, mais j'ai déjà repris des scripts faisant plusieurs centaines de lignes et honnêtement, avec des gestions de condition comme ça, je me prend pas la tête : je réécrit tout!
# Complètement imbitable...
Posté par liberforce (site web personnel) . Évalué à 10.
Apprends à faire des fonctions, des returns, et utiliser des codes d'erreur. Et youpi, pas besoin d'imbriquer plusieurs niveaux de if. Et ça marche pour d'autres langages.
Parce que là c'est à la limite de l'obfuscation de code... Fausse bonne idée. Je te conseille de lire la bible du bash: le Advanced Bash-Scripting Guide. Une traduction française plus ancienne du même guide est aussi disponible: Guide avancé d'écriture des scripts Bash.
[^] # Re: Complètement imbitable...
Posté par grondilu . Évalué à -2.
Il est absurde de créer une fonction pour une portion de code qu'on n'utilisera qu'une fois. Parce qu'ici foo et bar ne sont que des exemples mais ça pourrait être n'importe quel test, genre [[ "$1" = "dothis" ]] ou que-sais-je-encore.
Je persiste donc à penser que ce style d'utilisation des structures if est une bonne idée.
[^] # Re: Complètement imbitable...
Posté par liberforce (site web personnel) . Évalué à 6.
Je ne te dis pas de faire 15 fonctions, une pour chacun de tes tests, mais une où tu fais tes traitements, pour pouvoir faire un return. Ou alors tu peux faire des exit, mais en général on évite de mettre 15000 exit dans un programme. Code non testé, toussa...
[^] # Re: Complètement imbitable...
Posté par grondilu . Évalué à -2.
retourner le code d'erreur ne ne change pas grand chose à l'affaire.
[^] # Re: Complètement imbitable...
Posté par dr_home . Évalué à 5.
Le problème de ta structure, c'est qu'elle est contre-intuitive : tu codes un programme qui marche s'il a planté tout le long de son exécution.
De plus, tu as àmha mal compris ce qu'on t'as indiqué. Ce que tu peux faire c'est :
Comme ça la séquence est stoppée à la première erreur mais le code erreur peut encore être exploité...
[^] # Re: Complètement imbitable...
Posté par Matthieu Moy (site web personnel) . Évalué à 1.
Heureusement ;-)
Tu voulais dire $?, je suppose.
[^] # Re: Complètement imbitable...
Posté par gaaaaaAab . Évalué à 10.
argh !
j'ai trop vu de fonction de plusieurs milliers de lignes dans ma vie pour ne pas réagir. La ré-utilisabilité n'est pas la seule raison qui pousse à structurer du code en fonction. La maintenabilité (mot valise qui cache pleins de qualités du code) est un argument au moins aussi fort (voire plus fort selon moi) pour découper son code en fonction, même si c'est des fonctions de 3 lignes et même si elles ne sont utilisées qu'une seule fois.
[^] # Re: Complètement imbitable...
Posté par ymorin . Évalué à 8.
Permet moi de m'inscrire en faux. Meme pour du code lineaire, l'utilisation de fonctions est parfois tres interessant.
Exemple:
C'est tout de meme plus lisible qu'une fonctions avec 305 lignes de code.
Ensuite, tu utilises des prototypes pour les 3 sous-fonctions, tu mets leurs corps en bas, et tout de suite, la structure macroscopique du programme apparait : en fait, tu configures, tu utilises et tu liberes le bouzin. Ca devient lumineux ! ;-)
Ensuite, que ces trois fonctions soient compliquees, c'est pas grave, l'idee generale est la, visible du premier coup d'oeil.
Maintenant, si tu veux optimiser, et eviter trois appels de fonction (qui seront de toute facon invisibles par rapport au temps necessaire a executer le reste du code), tu declare tes fonction inline, et/ou static.. Et tout bon compilateur qui se respecte saura optimiser ca sans soucis.
Bien entendu, dans l'evolution n+27 de ton logiciel (que ton client te demanderas, style c'est juste une evolution mineure ! ;-] ), tu seras bien content d'avoir factorise tout ca, parce que tu auras non plus un, ni meme deux, mais 42 bouzins a configurer, utiliser plusieurs fois, et ensuite liberer !
Hop,
Moi.
PS. oui, je sais : les accents... J'ai juste oublier de reconfigurer compose sur la nouvelle becane... M'en vais faire ca de suite...
[^] # Re: Complètement imbitable...
Posté par windu.2b . Évalué à 6.
Les mouches devraient faire attention a leur cul, à toute heure...
[^] # Re: Complètement imbitable...
Posté par ckyl . Évalué à 2.
Y'a une autre raison de programmer en *sh qu'une volonté d'obfuscation et d'introduire des bugs improbables ? Attention j'ai dit programmer pas écrire 5 lignes de wrapper.
[^] # Re: Complètement imbitable...
Posté par Olorim . Évalué à 3.
Oui, vieux serveur UNIX de production sur lesquels on a pas le droit d'installer quoi que ce soit... Bienvenu dans le monde bancaire...
[^] # Re: Complètement imbitable...
Posté par barmic . Évalué à 3.
Il y a pas un interpréteur perl ou python et ils laissent un shell complet ?
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: Complètement imbitable...
Posté par Olorim . Évalué à 2.
Pas dans mes souvenirs
[^] # Re: Complètement imbitable...
Posté par dr_home . Évalué à 2.
Quels bugs improbables ? c'est comme dans toute programmation : à partir du moment où tu structures logiquement ton programme en petits traitements facilement testables isolément, ça tient la route. Après, effectivement, le shell a ses propres subtilités qui font qu'on ne pose pas à la base les problèmes de la même manière qu'en Perl ou qu'en Python. Mais une fois que tu as compris ça, pour les gros scripts il n'y a de mon point de vue pas plus de problèmes que dans les langages précédemment cités.
# Shell, illisible
Posté par 🚲 Tanguy Ortolo (site web personnel) . Évalué à 10.
C'est du Shell, pas du Bash. Je veux dire, ce n'est pas spécifique à Bash, et c'est donc utilisable dans tous les shells de type sh, en particulier dash.
Ceci étant, je vous déconseille fortement cette façon de coder, parce qu'elle est difficile à lire, or du code est fait pour être :
[^] # Re: Shell, illisible
Posté par gst . Évalué à 1.
2,5: élégant/joli/toussa :)
[^] # Re: Shell, illisible
Posté par kursus_hc . Évalué à 3.
On pourrait arrêter d'écrire "toussa" s'il vous plaît ?
[^] # Re: Shell, illisible
Posté par netsurfeur . Évalué à 6.
Je ne vois pas ce que tu reproches au passé simple du verbe tousser à la troisième personne du singulier. ;)
[^] # Re: Shell, illisible
Posté par CrEv (site web personnel) . Évalué à 7.
Ben finalement toussa say bien.
Arrête donc de faire ton maichant !
[^] # Re: Shell, illisible
Posté par barmic . Évalué à 3.
élégant/joli/*/
C'est tout de même plus simple est plus agréable.
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: Shell, illisible
Posté par gaaaaaAab . Évalué à 10.
tu veux dire plus simple, plus agréable, toussa ? :)
[^] # Re: Shell, illisible
Posté par Kerro . Évalué à 3.
[^] # Re: Shell, illisible
Posté par barmic . Évalué à 2.
J'ai pas fais gaffe markdown m'a bouffé la moitié.
élégant/joli/**/*
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: Shell, illisible
Posté par 🚲 Tanguy Ortolo (site web personnel) . Évalué à 2.
Ça rentre dans le point 1, ça. Puisque du code est fait pour être lu, il faut avant tout l'écrire pour faciliter cette lecture, et l'élégance est un bon moyen pour cela.
# set -eu + trap
Posté par Krunch (site web personnel) . Évalué à 2.
On m'a récemment fait découvrir set -eu. Associé à trap, je trouve ça assez pratique pour la gestion d'erreurs : il n'y a pas besoin de la mettre explicitement dans le code, ce qui le rend moins bloated et plus lisible. Le problème c'est pour les subshells par contre : http://fvue.nl/wiki/Bash:_Error_handling#Caveat_3:_.60Exit_on_error.27_not_exitting_command_substition_on_error
pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.
# au temps pour moi
Posté par grondilu . Évalué à 3.
Bon c'est vrai que la structure
est la plus adaptée dans 99% des cas. J'avoue que je l'avais juste oubliée.
Je viens de réécrire mon code avec ce type de gestion d'erreur, et c'est incontestablement plus lisible.
Le fait de pouvoir écrire une liste de commandes après un if ou un elif n'est pas si astucieux, donc.
désolé.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.