Précédent   Forum des professionnels en informatique > Systèmes > Linux > Applications > Shell
Shell Vos questions sur l'utilisation des commandes shell
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 18/06/2011, 00h14   #1
Membre du Club
 
Inscription : juillet 2006
Messages : 166
Détails du profil
Informations forums :
Inscription : juillet 2006
Messages : 166
Points : 61
Points : 61
Par défaut [bash] Pièges à éviter.

Je créé ce sujet car je n'ai rien trouvé d'équivalent sur ce site.

J'ai une toute jeune expérience du bash mais j'ai déjà rencontré un de ces pièges.

Bash ne supporte pas les if (elif inclus) et fonctions vides, il y faut au moins une instruction.

Code :
1
2
3
4
5
MaFonction {
}
 
if maCondition ; then
fi
Vous me direz, mais quel intérêt d'avoir une fonction ou un if vide ?
Aucun, sauf si on veut simplement faire le prototype et avancer plus loin dans une autre partie du code, pour y revenir ultérieurement.
Après on peut discuter du bien fondé d'une telle démarche, mais c'est un autre débat

Bref, pour pallier à cela il suffit d'ajouter une instruction qui ne modifie pas le déroulement du code, true ou false semble tout indiqué dans la plupart des cas.

Je précise que je n'ai trouvé aucune info à ce sujet dans le man de bash, et ça me semble tout sauf évident, j'ai jamais rencontré cela dans un autre langage script, personnellement j'ai perdu un temps fou à trouver cette cause, je pensais à tout sauf à cela.

Si vous pouviez faire part d'éventuelles autres infos de ce genre ici (si il y en a)
J'ai hésité à poster dans le sujet "truc et astuces", mais je trouvais que le sujet était différent, si le staff décide que ce n'est pas le cas, alors amen.
AnozerOne est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 18/06/2011, 16h58   #2
Membre éclairé
 
Avatar de FRUiT
 
Homme
Inscription : février 2011
Messages : 83
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 36
Localisation : France, Paris (Île de France)

Informations forums :
Inscription : février 2011
Messages : 83
Points : 326
Points : 326
http://mywiki.wooledge.org/BashPitfalls
__________________
Neon Suite by FRUiT (kde4.6) http://tinyurl.com/yzm7cee
"Pour la carotte, le lapin est la plus parfaite incarnation du mal" (R. Sheckley)
clean
FRUiT est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 19/06/2011, 16h58   #3
Expert Confirmé Sénior
 
Avatar de Sve@r
 
Homme Frédéric
Ingénieur développement logiciels
Inscription : février 2006
Messages : 3 055
Détails du profil
Informations personnelles :
Nom : Homme Frédéric
Âge : 44
Localisation : France, Oise (Picardie)

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : Aéronautique - Marine - Espace - Armement

Informations forums :
Inscription : février 2006
Messages : 3 055
Points : 4 934
Points : 4 934
Citation:
Envoyé par AnozerOne Voir le message
Bref, pour pallier à cela il suffit d'ajouter une instruction qui ne modifie pas le déroulement du code, true ou false semble tout indiqué dans la plupart des cas.

Je précise que je n'ai trouvé aucune info à ce sujet dans le man de bash, et ça me semble tout sauf évident, j'ai jamais rencontré cela dans un autre langage script, personnellement j'ai perdu un temps fou à trouver cette cause, je pensais à tout sauf à cela.

Si vous pouviez faire part d'éventuelles autres infos de ce genre ici (si il y en a)
Salut

Le principal problème du shell, c'est qu'il est très lent. Normal puisqu'il analyse chaque instruction. Et donc pour qu'il soit malgré tout le plus rapide possible, son moteur d'analyse a été réduit au minimum. Corollaire, un moteur d'analyse réduit n'est pas cablé pour analyser toutes les situations possibles.
Ce qui implique alors une syntaxe parfaite de la part du programmeur car sinon l'analyseur ne pigera rien.

Donc après un if, il faut un then et une instruction. Après un while et un for, il faut un do et une instruction. D'où ta solution d'utiliser l'instruction "true" ne faisant rien de visible. Tu aurais pu aussi mettre un simple point-virgule symbolisant l'instruction "rien"
Code bash :
1
2
3
4
if ...
then
    ;
fi

Autre danger du shell que j'ai déjà repéré mais qui peut causer souci à celui qui n'est pas habitué
Code bash :
1
2
3
4
5
6
7
8
9
10
11
while ...
do
    ...
    ...
    echo "Voulez-vous continuer ?"
    read rep
    if test $rep = non
    then
         break
    fi
done

Le danger de ce code vient si l'utilisateur tape "<return>" dans rien répondre. A ce moment là, la variable $rep est vide et le shell voit
Cette syntaxe est bancale car l'opérateur "=" veut absolument deux opérandes et ici il n'en voit qu'un seul. D'où le message sybillin "test:= unary opérator expected" signifiant qu'il s'attend à avoir un opérateur unaire en lieu et place du "=" vu qu'il ne voit qu'un seul opérande.

Pour pallier ce danger, toujours encapsuler les variables chaines par des guillemets
Code bash :
1
2
3
4
5
6
7
8
9
10
11
while ...
do
    ...
    ...
    echo "Voulez-vous continuer ?"
    read rep
    if test "$rep" = "non"
    then
         break
    fi
done

Si jamais la variable $rep" est vide, le shell verra
Code bash :
if test "" = "non"
Et là, il comprendra quand-même qu'il doit comparer 2 chaines...
__________________
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Tout ce qu'un individu reçoit sans rien faire pour l'obtenir, un autre individu a dû travailler pour le produire sans en tirer profit.
Tout Pouvoir ne peut distribuer aux uns que ce qu'il a préalablement confisqué à d'autres car on n'accroît pas les biens en les divisant.
Quand la moitié d'un peuple croit qu'il ne sert à rien de faire des efforts car l'autre moitié les fera pour elle, et quand cette dernière moitié se dit qu'il ne sert à rien d'en faire car ils bénéficieront à d'autres, cela s'appelle le déclin et la fin d'une nation.
Dr. Adrian Rogers, 1931
Sve@r est déconnecté   Envoyer un message privé Réponse avec citation 20
Vieux 19/06/2011, 17h27   #4
Membre du Club
 
Inscription : juillet 2006
Messages : 166
Détails du profil
Informations forums :
Inscription : juillet 2006
Messages : 166
Points : 61
Points : 61
@FRUIT : Merci pour le lien, je m'étais limité à quelles sources francophones, mais je dois dire que celle là à l'air d'être d'une meilleure qualité.

@Sve@r : : J'avais essayé une instruction vide ; mais bash me vomissait une erreur de syntaxe, as tu vraiment essayé cette solution ?

Merci pour le warning, même si je le savais déjà (je ne peux pas non plus être complètement ignorant )
AnozerOne est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/06/2011, 19h25   #5
Expert Confirmé Sénior
 
Avatar de Sve@r
 
Homme Frédéric
Ingénieur développement logiciels
Inscription : février 2006
Messages : 3 055
Détails du profil
Informations personnelles :
Nom : Homme Frédéric
Âge : 44
Localisation : France, Oise (Picardie)

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : Aéronautique - Marine - Espace - Armement

Informations forums :
Inscription : février 2006
Messages : 3 055
Points : 4 934
Points : 4 934
Citation:
Envoyé par AnozerOne Voir le message
@Sve@r : : J'avais essayé une instruction vide ; mais bash me vomissait une erreur de syntaxe, as tu vraiment essayé cette solution ?
Non désolé, j'ai fait une erreur de souvenir. C'est l'instruction ":" et non ";" (j'ai tapé mon post de mémoire)...

Mais puisqu'on est dans les petites subtilités du shell (je viens de lire http://mywiki.wooledge.org/BashPitfalls que j'ai trouvé pas mal du tout), j'ai remarqué un truc amusant sur les booléens

En effet, dans les langages classiques, un booléen n'est jamais examiné plus que nécessaire. Par exemple dans un if (e1 or e2 or e3), si e1 est vrai, alors l'évaluation ne s'embête pas à examiner e2 et e3 puisque le test est de toute façon vrai. Pareil pour un "et" qui serait faux dès la première expression.
Ce qui est pratique quand l'évaluation de e2 dépend de e1 comme les pointeurs en C
Code c :
if (pt != NULL && *pt == ...)

Mais pas en shell, comme le démontre le petit code suivant

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/sh
# Petit script démontrant le comportement d'une évaluation
 
# Test sur le "ou"
rm -f fichier1
ls -l fichier2
if test -n "$HOME" -o -z "$(>fichier1)"
then
	echo "gagné"
	ls -l fichier1
fi
 
# Test sur le "et"
rm -f fichier2
ls -l fichier2
if test -z "$HOME" -a -n "$(>fichier2)"
then
	:      # Juste pour te faire plaisir :mrgreen:
else
	echo "gagné"
	ls -l fichier2
fi
Dans le cas du "ou", comme la variable $HOME n'est pas vide, le "if" est définitivement vrai. Mais au résultat, on se rend compte qu'il a quand-même inutilement évalué l'instruction suivante laquelle va créer le fichier n° 1 (ce qu'on voit lors du "ls")

Et idem dans le cas du "et" où le fichier n° 2 est inutilement créé alors que le "if" est déjà définitivement faux...
__________________
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Tout ce qu'un individu reçoit sans rien faire pour l'obtenir, un autre individu a dû travailler pour le produire sans en tirer profit.
Tout Pouvoir ne peut distribuer aux uns que ce qu'il a préalablement confisqué à d'autres car on n'accroît pas les biens en les divisant.
Quand la moitié d'un peuple croit qu'il ne sert à rien de faire des efforts car l'autre moitié les fera pour elle, et quand cette dernière moitié se dit qu'il ne sert à rien d'en faire car ils bénéficieront à d'autres, cela s'appelle le déclin et la fin d'une nation.
Dr. Adrian Rogers, 1931
Sve@r est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/06/2011, 19h44   #6
Membre du Club
 
Inscription : juillet 2006
Messages : 166
Détails du profil
Informations forums :
Inscription : juillet 2006
Messages : 166
Points : 61
Points : 61
Ok, rien de bien important à priori mais cela met la valeur $? à 0, dans certains cas l'emploi de false à la place peut donc être utile.
Mais dans la mesure où l'on parle d'un code qui n'est pas fini ...

EDIT : Pour les booléens ca ne s'applique que pour test expression et [ expression ] (qui est la même chose avec une syntaxe différente mais pas pour [[ expression ]].
Cela s'applique aussi pour les conditions liées par des && ou des ||

J'avais mal lu

Même si cette dernière forme [[ expression ]] n'est pas compatible avec le sh (mais l'est pour bash et ksh, et surement d'autres shell), elle est plus puissante.

Plus d'explications dans cette page.
(j'étais justement en train de la lire )

Le problème vient quand on a plus de 2 tests ainsi en série, dès fois le comportement du shell n'a pas vraiment de sens
AnozerOne est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/06/2011, 19h59   #7
Expert Confirmé Sénior
 
Avatar de Sve@r
 
Homme Frédéric
Ingénieur développement logiciels
Inscription : février 2006
Messages : 3 055
Détails du profil
Informations personnelles :
Nom : Homme Frédéric
Âge : 44
Localisation : France, Oise (Picardie)

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : Aéronautique - Marine - Espace - Armement

Informations forums :
Inscription : février 2006
Messages : 3 055
Points : 4 934
Points : 4 934
Citation:
Envoyé par AnozerOne Voir le message
Pour les booléens ca ne s'applique que pour test et [ expression ] (qui est la même chose avec une syntaxe différente mais pas pour [[ expression ]].
Oui. Toutefois comme je développe dans du multi environnement, j'essaye d'avoir un shell 100% compatible Bourne Shell de base donc pour moi, [[...]] c'est interdit.

Citation:
Envoyé par AnozerOne Voir le message
Cela s'applique aussi pour les conditions liées par des && ou des ||
Là ce n'est plus pareil. Le && et || sont des connecteurs d'instructions. e1 && e2 n'ira exécuter e2 que si e1 est vrai. Normal que si e1 soit faux, e2 ne soit pas exécuté
Moi je parlais de l'évaluation interne faite par l'instruction "test" laquelle aurait-pu être un poil plus poussée (simplifiée peut-être ?)...

Citation:
Envoyé par AnozerOne Voir le message
Même si cette dernière forme n'est pas compatible avec le shell
Arf non, le Bourne Shell de base connait parfaitement les "&&" et "||"
Citation:
Envoyé par AnozerOne Voir le message
elle est plus puissante.
Je ne sais pas. Je ne suis pas certain qu'il soit judicieux de remplacer un
qui n'appelle qu'une fois l'instruction; en
qui l'appellera 2 fois...
__________________
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Tout ce qu'un individu reçoit sans rien faire pour l'obtenir, un autre individu a dû travailler pour le produire sans en tirer profit.
Tout Pouvoir ne peut distribuer aux uns que ce qu'il a préalablement confisqué à d'autres car on n'accroît pas les biens en les divisant.
Quand la moitié d'un peuple croit qu'il ne sert à rien de faire des efforts car l'autre moitié les fera pour elle, et quand cette dernière moitié se dit qu'il ne sert à rien d'en faire car ils bénéficieront à d'autres, cela s'appelle le déclin et la fin d'une nation.
Dr. Adrian Rogers, 1931
Sve@r est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/06/2011, 20h08   #8
Membre du Club
 
Inscription : juillet 2006
Messages : 166
Détails du profil
Informations forums :
Inscription : juillet 2006
Messages : 166
Points : 61
Points : 61
Citation:
Envoyé par Sve@r Voir le message
Oui. Toutefois comme je développe dans du multi environnement, j'essaye d'avoir un shell 100% compatible Bourne Shell de base donc pour moi, [[...]] c'est interdit.
Je n'ai pas cette contrainte, étant simplement amateur

Citation:
Là ce n'est plus pareil. Le && et || sont des connecteurs d'instructions. e1 && e2 n'ira exécuter e2 que si e1 est vrai. Normal que si e1 soit faux, e2 ne soit pas exécuté
Et pourtant :

Citation:
But there's a problem. When we have a sequence of commands separated by Conditional Operators, Bash looks at every one of them, in order from left to right. The exit status is carried through from whichever command was most recently executed, and skipping a command doesn't change it.
EDIT : Ok, erreur de logique de ma part, je pense que je vais arrêter les frais pour aujourd'hui ...


Citation:
Moi je parlais de l'évaluation interne faite par l'instruction "test" laquelle aurait-pu être un poil plus poussée (simplifiée peut-être ?)...
En fait j'ai édité mon message cela s'applique aussi avec [[ ]]


Citation:
Arf non, le Bourne Shell de base connait parfaitement les "&&" et "||"
L'intérêt n'est pas là (cette phrase était mal placé avant mon edit), mais je ne peux pas mieux expliquer que le lien que j'ai précédemment donné, et puis tu dois déjà le savoir de toute façon.

Citation:
Je ne sais pas. Je ne suis pas certain qu'il soit judicieux de remplacer un
qui n'appelle qu'une fois l'instruction; en
qui l'appellera 2 fois...
Et pourtant il y en a un (le lien que j'ai donné explique cela très bien), ce qui semble d'ailleurs être le problème de ton exemple.

Citation:
Don't ever use the -a or -o tests of the [ command. Use multiple [ commands instead (or use [[ if you can). POSIX doesn't define the behavior of [ with complex sets of tests, so you never know what you'll get.
AnozerOne est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 01h17.


 
 
 
 
Partenaires

Hébergement Web