Bonjour,
J'ai écrit un script bash avec quelques fonctions et j'ai un petit problème.
Comme son nom l'indique, la fonction end_script met fin à l'éxécution du script en expliquant l'origine (passée en variable) de l'erreur.
end_script()
{
local args
local exit_code
local reason
args="$#"
exit_code="$1"
reason="$2"
[ "$args" = 2 ] \
&& printf "%s\n" "Error : $reason"
printf "%s\n\n" "End of the script."
exit "$exit_code"
}
J'ai ensuite une fonction qui teste si une variable est définie :
is_empty()
{
local var
var="$1"
[ -z "$var" ]
}
Le test se fait ensuite simplement avec :
is_empty "$DIR_SRC" \
&& end_script "1" "the user variable \"DIR_SRC\" is not set."
Et cela produit le résultat escompté.
Je voudrais simplifier avec un truc dans ce genre :
is_empty()
{
local var
var="$1"
[ -z "$var" ] \
&& end_script "1" "the user variable $var is not set."
}
is_empty "$DIR_SRC"
Mais cela ne marche pas.
Au lieu d'obtenir "the user variable $DIR_SRC is not set.", j'obtiens "the user variable is not set."
Donc moins précis sur la cause de l'erreur.
Auriez-vous une idée sur comment atteindre le résultat souhaité ?
# Évaluation en deux temps
Posté par Cyril Brulebois (site web personnel) . Évalué à 3.
Tu obtiens même
the user variable is not set.
avec deux espaces. ;)Il y a une légère confusion : tu essaies de passer à ta fonction le nom de ta variable ou son éventuel contenu ?
Si tu passes son nom à la fonction, il va falloir demander à ton shell d'aller chercher son contenu. Cela peut se faire en utilisant
eval
(qui n'est pas trivial car il faut penser à la double évaluation que cela implique).Si tu passes son contenu à la fonction, celle-ci n'a pas accès à son nom. Elle ne peut donc pas l'utiliser dans un éventuel message d'erreur.
Debian Consultant @ DEBAMAX
[^] # Re: Évaluation en deux temps
Posté par NBaH . Évalué à 2. Dernière modification le 12 juin 2020 à 14:36.
en bash, on peut passer une variable par référence :
on exécute ainsi :
[^] # Re: Évaluation en deux temps
Posté par gzgtrhe . Évalué à 1.
Merci pour eval.
Après avoir googlé, je suis arrivé à ça :
Avec le résultat que je recharchais :
Cela fait le boulot comme demandé mais cela génère un nouveau problème : la variable passé à la fonction "is_empty" ne doit avoir le symbole $, sinon eval ne marche pas.
Du coup ça permet d'enlever des lignes de code dans le script mais l'utilisation de DIR_SRC est moins lisible :-(
[^] # Re: Évaluation en deux temps
Posté par NBaH . Évalué à 2.
je vais plutôt rester sur le passage de variable par référence.
[^] # Re: Évaluation en deux temps
Posté par NeoX . Évalué à 2.
je dis surement une bêtise mais avec un
var1=eval $1
ca devrait remplir var1 avec le contenu de $1
tu appelles ensuite
is_empty $DIR_SRC
[^] # Re: Évaluation en deux temps
Posté par Cyril Brulebois (site web personnel) . Évalué à 1.
Oui. Ce que tu proposes appelle le contenu de
$1
en tant que commande en positionnant temporairementvar1
àeval
…Debian Consultant @ DEBAMAX
# une bien belle fonction...
Posté par NBaH . Évalué à -3.
mais tellement inutile.
[^] # Re: une bien belle fonction...
Posté par gzgtrhe . Évalué à 3.
Bonjour,
Pourquoi donc ?
Je ne suis pas administrateur système ni développeur, donc si vous pouviez m'expliquer en quoi je me suis trompé… :-)
[^] # Re: une bien belle fonction...
Posté par NBaH . Évalué à -2.
il est inutile de faire une fonction pour un simple test.
[^] # Re: une bien belle fonction...
Posté par _kaos_ . Évalué à 3.
Salut,
Au début, je voulais répondre, puis j'ai laissé de côté. Puis j'ai vu que l'OP t'avais répondu et toi aussi.
Donc là, ça me gratte trop ce que j'avais en tête : parfois, faire du code complètement inutile, c'est bon pour la compréhension.
J'ai l'impression (je peux me tromper) que l'OP est juste en train d'apprendre. Et que les bases sont pas bancales, juste besoin d'un peu d'aide (que je ne peux malheureusement pas apporter pour du shell).
Je me souviens des cours d'algo que je donnais il y a longtemps, basés sur les tris. Est-ce que je commençais par le tri rapide ? Non. Ça commençait plus par le tri bulle, complètement inefficace la plus part du temps. Donc les élèves étaient prévenu, hein, genre : Ça c'est super débile, mais à la fin, on arrivera peut-être au tri rapide si vous suivez.
Faire du code, même mort né, si on apprend, c'est un bon moyen de comprendre.
Bref, tout dépend de ce que tu veux au final.
Matricule 23415
[^] # Re: une bien belle fonction...
Posté par nico4nicolas . Évalué à 6.
C'est ton commentaire que j'ai noté comme inutile car :
[^] # Re: une bien belle fonction...
Posté par NBaH . Évalué à 0.
tu as du mal à interpréter
test
?bof, à la rigueur, si le test est répété dans le script dans les mêmes conditions.
mais, je ne vais pas réécrire une fonction pour chaque option de chaque commande du shell pour ça.
[^] # Re: une bien belle fonction...
Posté par nico4nicolas . Évalué à 3.
ou
Oui, je prétends que dans le premier cas le lecteur doit interpréter que le test est fait pour savoir s'il s'agit d'un string "vide" alors que dans le deuxième cas, c'est écrit. Dans le deuxième cas, on se concentre sur ce qui est fait pas comment cela est fait.
Un des principes de base de la fonction, c'est d'éviter la duplication de code en écrivant à un seul endroit ce qui est fait dans de nombreux endroits. Si les tests que tu veux faire n'ont rien en commun, c'est effectivement "inutile". En ignorant l'utilisation qui est faite de la fonction proposée, il m'apparait bien délicat de dire que faire une fonction pour un test est "inutile" (sauf à des fins de compréhension ou d'apprentissage) comme tu le prétendais dans ton commentaire initial.
[^] # Re: une bien belle fonction...
Posté par gzgtrhe . Évalué à 2.
Je fais subir à quelques variables les mêmes tests.
Il m'a donc paru préférable de faire une fonction pour ça (les autres fonctions de test sont similaires). En plus, cela me permet d'apprendre les subtilités du scripting :-)
[^] # Re: une bien belle fonction...
Posté par vv222 . Évalué à 4.
Je suis administrateur système et développeur. Je t’affirme donc en connaissance de cause que ta fonction
is_empty
est une idée très intelligente, et même la base d’un code maintenable sur le long terme.À chaque fois qu’un "développeur" prétendra qu’il peut faire la même chose en moins de lignes de codes que toi, ignore-le. Tout le monde préfère collaborer avec ceux qui privilégient un code verbeux et facile à comprendre.
[^] # Re: une bien belle fonction...
Posté par NBaH . Évalué à 0.
oh oui, soyons moyen.
[^] # Re: une bien belle fonction...
Posté par gzgtrhe . Évalué à 1.
Merci mais ce n'est pas la mienne.
Je l'ai pompé depuis ce site qui a été donné en réponse à un utilisateur cherchant justement quelles sont les bonnes pratiques pour écrire du code :-)
https://blog.seboss666.info/2020/04/programmation-defensive-en-bash/
[^] # Re: une bien belle fonction...
Posté par Nodeus . Évalué à 3.
Même si je suis tout à fait d'accord avec une utilisation intense des fonctions.
J’emmétrai juste quelques observations :
Il me semble que plus il y a de lignes de code, plus il y a de risques de bugs.
D'une autre part, le principe de base de la programmation est d'éviter de recoder des instructions natives du langage non ?
Mais je peux me tromper
[^] # Une dernière remarque
Posté par Nodeus . Évalué à 1.
Je m'étonne juste que les codes retour des fonctions bash ne soient pas utililisés et testé.
[^] # Re: une bien belle fonction...
Posté par _kaos_ . Évalué à 2.
Salut,
Alors ça, c'est un beau fantasme. ;)
Moi, je fais principalement du java, là, c'est super verbeux, mais si quelqu'un d'autre passe par derrière, si tu n'a pas "foiré" ta logique, c'est assez rapide à comprendre au final. Je fais un peu de python de temps en temps aussi. Ça peut être parfois un peu plus compact (enfin, normalement pas beaucoup plus), et parfois du R.
Et là, ça compacte beaucoup plus si tu as changé de manière de programmer. Et c'est une autre paire de manche pour comprendre si ce n'est pas toi qui a écrit le code.
Je n'ai jamais vu un programme trop long en termes de lignes de code. S'il y a une structure pensée, ce n'est pas le nombre de lignes qui importe. C'est de pouvoir lire, comprendre, et taper là où ça fait mal, si y'a bug.
Matricule 23415
[^] # Re: une bien belle fonction...
Posté par Nodeus . Évalué à 3.
Je me rappelle trois conseils des mes profs d'informatique dans la rédaction d'un programme :
-Soyez concis dans votre rédaction (programmation)
-Faites des fonctions , procédures ou méthodes
-Si une méthode , procédure ou une fonction fait plus de 15 lignes c'est que vous pouvez la décomposer.
et un dernier conseil important.
Ne réinventez pas la roue :D
Et ça marche assez bien.
[^] # Re: une bien belle fonction...
Posté par Ysabeau 🧶 (site web personnel, Mastodon) . Évalué à 3. Dernière modification le 09 juin 2020 à 16:35.
Zut, je me suis trompée de bouton en voulant répondre (ne jamais faire trois choses à la fois) et j'ai moinsé alors que ça valait largement d'être pertinenté. Désolée et pas moyen de corriger le tir.
Bref c'est ce genre de conseil que j'ai aussi tendance à donner pour la conception de formules dans un tableur, la décomposition des étapes permet un meilleur contrôle et une meilleure évolution de la formule finale. Quand la formule est très longue, on n'y voit plus rien. Ça fait moins formule magique, mais c'est plus fiable.
« Tak ne veut pas quʼon pense à lui, il veut quʼon pense », Terry Pratchett, Déraillé.
[^] # Re: une bien belle fonction...
Posté par _kaos_ . Évalué à 3.
Salut,
Oui, c'est pas trop mal comme approche, même s'il faut savoir sortir des clous par moment. Enfin, quand c'est le moment.
J'ai déjà eu le cas de conscience. Un petit problème de validation de données à résoudre en mode "la rache".
J'avais déjà lu "le" truc là dessus. Donc je ne partais pas en terrain inconnu ;)
Je pouvais partir dans plein de classes, pour expliquer tout ça, mais il fallait aller vite. Donc ça c'est fini en une regexp one-liner. Et un super gros commentaire au dessus : Touchez pas à cette ligne en dessous !
Parfois, chercher la concision (ou le nombre minimal de ligne), ce n'est pas la bonne approche. Parce que personne d'autre ne comprendra.
Matricule 23415
[^] # Re: une bien belle fonction...
Posté par Nodeus . Évalué à 2. Dernière modification le 09 juin 2020 à 23:33.
Je dis simplement qu'utiliser cette fonction
end_script()
{
local args
local exit_code
local reason
args="$#"
exit_code="$1"
reason="$2"
[ "$args" = 2 ] \
&& printf "%s\n" "Error : $reason"
printf "%s\n\n" "End of the script."
exit "$exit_code"
}
is_empty()
{
local var
var="$1"
[ -z "$var" ]
}
is_empty "$DIR_SRC" \
&& end_script "1" "the user variable \"DIR_SRC\" is not set."
plutôt que
[ -z "$DIR_SRC" ] \
&& printf "%s\n%s\n" "the user variable \"DIR_SRC\" is not set." "End of the script." \
&& exit 1
c'est pousser le bouchon un peu loin.
après le site fait de la programmation défensive :
Il faut aussi dire plus il y'a de code plus la surface d'attaque est grande.
Je pense qu'il faut maîtriser la sémantique d'un langage pour l'utiliser.
vouloir faire se ressembler tous les langages de programmation est une utopie.
Comme dirait Guenièvre un moment pour faire du cheval il faut faire du cheval.
Pour le shell et le bash en particulier c'est pareil. On peut utiliser des bonnes pratiques pour sécuriser la programmation mais il ne faut pas nier les spécificités du langage.
Il ne faut pas oublié non plus d'être rigoureux : il n'y a pas de mauvais langage…
[^] # Re: une bien belle fonction...
Posté par nico4nicolas . Évalué à 3.
Même si la fonction est appelée 50 fois ?
[^] # Re: une bien belle fonction...
Posté par Nodeus . Évalué à 2.
Bonne remarque :
bien en l’occurrence elle ne peux être appeler qu'une seule fois au vue du exit à la fin.
bref passons sur cet argument discutable( mais pas tant que ça).
Elle sera plutôt appeler à 50 emplacements différents dans le programme mais exécutée une seule fois.
comme je disais dans le post précédent je suis pour les fonction et dans ce cas cette méthode est très bien dans le cadre d'une programmation sur des scripts qui ont besoin d'une bonne rigueur pour éviter de construire des script non maintenable.
Mais il faut juste "raison garder" , si on suis jusqu'au bout le principe on fini par tout recoder en fonction.
et pourquoi pas
une fonction :
pour s’assurer d'avoir toujours un entier en retour
affecteint() {
local var ;
var="${1}"
var={var}" )
return $var
}
affecteint 10
monentier=$?
est-ce bien judicieux?
[^] # Re: une bien belle fonction...
Posté par nico4nicolas . Évalué à 2.
Tout à fait, c'est un problème de formulation de ma part mais c'est à cela que je pensais. Merci pour la correction.
Effectivement, cet exemple semble peu judicieux mais je garderais cette fonction bien volontiers si elle venait valider l'input d'un utilisateur pour avoir le même comportement dans le cas d'une entrée erronée/inattendue.
[^] # Re: une bien belle fonction...
Posté par Nodeus . Évalué à 2. Dernière modification le 10 juin 2020 à 13:50.
en shell pour avoir une réponse normalisée et sans input inattendue.
Le plus simple est de créer un menu ou une liste d'options définies et valide toute autre réponse doit renvoyer une erreur.
tant qu'a permettre une saisie encadrez la
[^] # Re: une bien belle fonction...
Posté par _kaos_ . Évalué à 3.
Salut,
Désolé de ne toujours pas être d'accord (même si je comprends tes arguments).
Au risque de me planter, il me semble que l'OP a indiqué dans un autre commentaire qu'il était dans une phase "découverte", ou "apprentissage", ou met le mot que tu souhaite.
C'est super contre-productif à ce stade (même si j'ai l'impression qu'il ne part pas de rien du tout) de bourriner sur l'optimisation dès le début à mon avis.
Ce n'est pas grave/gênant quand tu fais ton petit projet de commencer avec juste des approximations. Ça peut être une version qui ne verra pas la sortie parce qu'une fois les problèmes plus complexes compris, la version 2 sera peut-être déjà dans les bacs.
Mode 3615 MyLife : je ne compte plus le nombre de personnes que je vois arriver avec un truc du style « Mon code marche pas sur 10 millions de lignes ! A l'aide ! ». Et où là, je suis presque obligé de leur demander s'il marche sur un échantillon (parfois c'est pas moi :) ). En général, non. Le problème est structurel, pas la donnée. Donc, la réponse, c'est "fais un code qui marche sur un échantillon, déjà, on voit pour l'optimisation après".
Matricule 23415
[^] # Re: une bien belle fonction...
Posté par Nodeus . Évalué à 0.
Pour faire une découverte, je conseille de ne pas commencer par de la programmation défensive en bash.
Il faut apprendre un langage dans toutes ses spécificités en commençant du général au particulier.
c'est pas de l'optimisation la fonction ci-dessus c'est un exemple un peu absurde et ç'est tout sauf du K.I.S.S.
Donc apprenez un langage en respectant sa nature.
On ne transforme pas du bash en python.
Mode 3615 MYlife : ça me rappel un garçon fan de programmation objet et qui pour un projet ou le langage imposé était le c normal pour de bonnes raison à l'époque avait pondu un système de macros pour générer des pseudo-objets et pouvoir faire de la programmation objet faisant augmenter le volume de code et la complexité du programme et posé des problèmes sur le projet.
[^] # Re: une bien belle fonction...
Posté par vv222 . Évalué à 3.
Forcément, ici la fonction
end_script
est un bricolage de la part de quelqu’un qui découvre ses outils ;)Voici ce qui est finalement la même fonction après s’être frottée à quelques cas supplémentaires :
source
source
[^] # Re: une bien belle fonction...
Posté par Nodeus . Évalué à 2. Dernière modification le 10 juin 2020 à 14:09.
Dans le cas de tes fonctions elle apportent des fonctionnalités supplémentaires au programme.
Je pense que notre OP n'a pas pris la voie la plus facile :D
Dans le cas de la programmation Défensive
On structure pour éviter les débordements dus à une mauvaise maîtrise du langage.
Je ne dis pas que c'est mal je dis simplement qu'il ne faut pas allez trop loin jusqu'a dénaturer le langage.
[^] # Re: une bien belle fonction...
Posté par vv222 . Évalué à 3.
Il va falloir que j’aille lire ça, que je ne connais pas encore mais qui commence à revenir pas mal dans la discussion. J’admets de suite que le titre de l’article ne me donne pas un a priori positif…
[^] # Re: une bien belle fonction...
Posté par Nodeus . Évalué à 2.
L'article est correcte c'est juste que l'objectif est de montrer comment durcir un script pour éviter des attaques utilisants les tolérances d'un langage permissif.
Et pas apprendre à utiliser le bash.
[^] # Re: une bien belle fonction...
Posté par NBaH . Évalué à 2.
il faut le dire bien fort, parce que
ls | commande
ou
commande | grep | awk
ce n'est pas possible.
c'est bizarre d'indiquer de bonnes pratiques en en utilisant de mauvaises…
[^] # Re: une bien belle fonction...
Posté par vv222 . Évalué à 3.
Avertissement : Je n’ai aucune formation académique, mes connaissances en développement en général et en shell en particulier viennent essentiellement de la lecture de pages de man. Et d’années de pratique.
Bah finalement, après lecture, je ne suis pas d’accord ;)
J’y vois un mélange de "bonnes pratiques" répétées sans forcément les comprendre, de conseils complètement absurdes (« Les symboles doivent être en début de ligne. », gni ??), et de mauvaise connaissance des outils (cf. la réponse de NBaH).
D’ailleurs je suis à peu près certain que le code donné dans les exemples ferait hurler ShellCheck, qui est étonnamment absent de ce guide.
[^] # Re: une bien belle fonction...
Posté par Nodeus . Évalué à 2.
Après une seconde lecture je pense que tu as raison l'article n'est pas terrible.
Sinon ShellCheck est un outil que j'adore pour améliorer la sécurité des script shell.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.