#1 Le 14/05/2008, à 20:59
- cidou
[resolu][Bash] Divers questions et problèmes sur les scripts-bash
Bonjours à tous, je vais vous montrer des scripts et j'aimerais bien avoir certaines précisions sur la raison de leur disfonctinnement, si possible en généralisant par la suite!
#!/bin/bash
#fonction qui renvoie vrai quand l'argument qui lui est passé en parametre est un nombre (positif ou négatif)
function isnum {
echo "$1" | grep -q '[-+]*[0-9]\+$'
}#script qui compare le deuxieme argument au deux autres, celui du milieu doit etre inférieur au troisieme mais supérieur au #premier
if (($# != 3 )) ; then
exit 2elif ! isnum $1 || ! isnum $2 || ! isnum $3 ; then
#ma meme version (fausse de la ligne ci-dessus)
#elif ! (isnum $1 || isnum $2 || isnum $3 ); thenexit 2
elif (( $2 > $1 && $2 < $3 )) ; then
# encore ma version, fausse :x
#elif (( $2 > $1 ) && ( $2 < $3 )) ; then
#ou pourquoi pas
#elif [ $2 > $1 && $2 < $3 ] ; thenecho "bien joué"
exit 0
else
exit 1
fi
Voila, j'ai indiqué les deux lignes qui m'interloque ! Celle étant en commentaire étant la mienne bien sur
Et j'aurais également voulus savoir quel était la différence entre l'utilisation des crochets [] et des parenthèses () pour entourer certaines expressions!
En vous remerciant d'avance!!
Dernière modification par cidou (Le 16/05/2008, à 14:05)
Pourquoi aller voter aux européennes ? ::
http://www.numerama.com/magazine/12948- … u-net.html
Hors ligne
#2 Le 14/05/2008, à 21:44
- snapshot
Re : [resolu][Bash] Divers questions et problèmes sur les scripts-bash
oula ! le shell est souvent pointilleux, et en faisant ce genre de truc, c'est normal de se planter !
Commençons par le plus facile : la différence entre l'utilisation des crochets [] et des parenthèses ()
En fait, si tu regardes dans /usr/bin, tu verras un exécutable nommé « [ » (crochet ouvrant) qui est souvent un lien symbolique vers « test »
Cela veut dire que :
if [ -z "$var" ]
est exactement la même chose que :
if test -z "$var"
La seule différence, c'est que si le programme test voit qu'il a été invoqué sous la forme crochet ouvrant, alors il exige que le dernier argument soit un crochet fermant... tout ça pour faire joli dans les if et while du shell ! mais on peut utiliser indifféremment l'un ou l'autre forme, c'est pareil
Pour le reste, je regarde, mais il y a des choses qui me paraissent douteuses...
Pensez à mettre [Résolu] dans le titre une fois votre problème réglé !
Hors ligne
#3 Le 14/05/2008, à 21:51
- cidou
Re : [resolu][Bash] Divers questions et problèmes sur les scripts-bash
Ok!! Je n'avais pas vus cette subtilité !! Je te remercie bcp ca m'éclaire déjà sur un point !
Pour ce qui est du reste, sache que le script que j'ai mis fonctionne parfaitement apres les correction, et j'aurais voulus savoir pourquoi ce que j'avais pensé en premier (ce qui est en commentaire) ne fonctionnait pas.
J'ai encore plein d'autre question, mais pour ne pas faire un post en bordel je les posterais une fois mes premières questions résolus !! Avis au courageux ! (ca y va creshendo
)
ps : *snapshot : dit moi ce qu'il te parrait douteux stp
Dernière modification par cidou (Le 14/05/2008, à 21:52)
Pourquoi aller voter aux européennes ? ::
http://www.numerama.com/magazine/12948- … u-net.html
Hors ligne
#4 Le 14/05/2008, à 21:51
- snapshot
Re : [resolu][Bash] Divers questions et problèmes sur les scripts-bash
Ta regexp dans la fonction isnum me parait trop laxiste... Elle considère blabla45 comme un numérique !, tout comme +-+-+-+-9 qui est certes mathématiquement valable, mais peu orthodoxe !
J'aurais mis ceci :
function isnum {
echo "$1" | egrep -q '^[-+]?[0-9]+$'
}
En utilisant egrep au lieu de grep, on utilise les regexp étendues dont la syntaxe est un peu plus conviviale (pas besoin de mettre « \+ » mais « + » tout simplement)
Pensez à mettre [Résolu] dans le titre une fois votre problème réglé !
Hors ligne
#5 Le 14/05/2008, à 21:58
- cidou
Re : [resolu][Bash] Divers questions et problèmes sur les scripts-bash
oui tu as tout à fait raison, d'ailleurs la correction de mon script indiquait clairement le '^' mais je n'avais pas pensé que son abscence fausserait autant que ca l'expression régulière.
ps : je ne connaissais pas egrep, et même si il m'a l'air plus puissant je me limiterais à grep(du moins pour l'instant), vus que j'ai déjà appris option et expression par coeur et que mon devoir et samedi matin :x
Pourquoi aller voter aux européennes ? ::
http://www.numerama.com/magazine/12948- … u-net.html
Hors ligne
#6 Le 14/05/2008, à 22:06
- snapshot
Re : [resolu][Bash] Divers questions et problèmes sur les scripts-bash
Ensuite, on fait souvent une erreur quand on passe d'un langage comme le C ou le python au shell, c'est de croire que ce qui suit un if ou un while est une suite d'opérateur. Et bien non, dans un shell, ce qui suit un if ou un while est un programme. Et c'est trompeur, car la plupart du temps, ce programme est [ (qui est en fait test), dont les arguments entre crochets sont effectivement des opératueurs ! Voilà où est l'astuce.
Ainsi, on à tout à fait le droit d'écrire des trucs du style :
- if ping -c 1 forum.ubuntu-fr.org ; then ...
- if rm fichier; then ...
- while read var; do ....
et donc :
- if [ -z "$var" ] ; then ....
Tout cela pour dire que
elif [ $2 > $1 && $2 < $3 ]
ne peut pas marcher : le programme [ (test) sera donc lancé avec les 7 arguments suivants :
- $2
- >
- $1
- &&
- $2
- <
- $3
mais ceux-ci ne figurent pas dans ses options ! -> man test
Pour comparer des numériques, il faut utiliser -gt (greater than), et pour le and, c'est -a
Donc, ça s'écrit ainsi dans la syntaxe de test :
elif [ "$2" -gt "$1" -a "$2" -lt "$3" ]
et il faut prendre l'habitude de mettre entre guillemets les variables : si l'une d'entre elles est vide, ça fera au moins une chaine vide à comparer, ce qui ne provoquera pas l'erreur de syntaxe qui arriverait s'il n'y avait rien du tout à la place.
Pensez à mettre [Résolu] dans le titre une fois votre problème réglé !
Hors ligne
#7 Le 14/05/2008, à 22:23
- snapshot
Re : [resolu][Bash] Divers questions et problèmes sur les scripts-bash
Ensuite, là ou ça devient délicieusement vicieux , c'est pourquoi
ceci marche :
elif (( $2 > $1 && $2 < $3 )) ; then
mais pas ça :
elif (( $2 > $1 ) && ( $2 < $3 )) ; then
en fait, la double parenthèse est considérée comme une seule parenthèse spéciale par le shell, qui introduit une syntaxe d'évaluation arithmétique. S'il y avait eu plus de signes ouvrants sur le clavier (autre que {, (, [, et <), un tel signe aurait été utilisé pour faire la différence. Comme ce n'était pas le cas, les concepteurs de bash ont du faire avec le peu qu'ils avaient. Aujourd'hui c'est le cas avec l'unicode et les caractères spéciaux de la touche AltGr. Donc imagine qu'ils aient utilisé ⊂ à la place de (( et ⊃ à la place de )). Tu comprends tout de suite pourquoi ceci fonctionne :
elif ⊂ $2 > $1 && $2 < $3 ⊃ ; then
mais pas ceci :
elif ⊂ $2 > $1 ) && ( $2 < $3 ⊃ ; then
tout simplement parce que les parenthèses ne sont pas balancées !
Et tu vois, je ne savais même pas que la construction « if (( .... )); then » fonctionnait !
Dernière modification par snapshot (Le 14/05/2008, à 22:36)
Pensez à mettre [Résolu] dans le titre une fois votre problème réglé !
Hors ligne
#8 Le 14/05/2008, à 22:33
- cidou
Re : [resolu][Bash] Divers questions et problèmes sur les scripts-bash
Pour être vicieux c'est vicieux :x , j'ai donc testé la formulation parenthésées avec ceci :
elif ((($2 > $1) && ($2 < $3))); then
Et la ca marche !! ;D mais bonjours le truc
Je vais donc garder la notation (( *liste* )) qui me semble la plus_mieux !!
Et vus que t'es bien partie tu penses quoi des OU_SINON !?
J'te remercie vraiment gars, ca m'éclaire vraiment tes explications !
ps : pour ce qui est des doubles parenthèse, n'en serrait t'il pas de même avec les boucle for des languages évolués ? (toujours en utilisation sous bash)
Dernière modification par cidou (Le 14/05/2008, à 22:37)
Pourquoi aller voter aux européennes ? ::
http://www.numerama.com/magazine/12948- … u-net.html
Hors ligne
#9 Le 14/05/2008, à 22:49
- snapshot
Re : [resolu][Bash] Divers questions et problèmes sur les scripts-bash
les OU_SINON ??? c'est-à-dire ???
y'a un autre truc qui me heurte, c'est de voir
if (($# != 3 )) ; then
exit 2
... hum, un programme qui plante en unix ne doit jamais mourir silencieusement ! En unix, c'est la règle du « qui ne dit rien consent » : si j'exécute un truc (comme mv, rm, tar...) et que ça revient sans rien dire, c'est que ça a marché, sinon, il y a un message d'erreur.
C'est ton script, tu sais comment il réagit. Mais un habitué d'unix sera dérouté. Et le code de retour d'erreur, c'est bon pour les scripts, mais pas pour les humains .
Donc, il faut écrire dans les règles de l'art :
if (($# != 3 )) ; then
echo $0: trois arguments sont nécessaires >&2
exit 2
le "$0:" c'est pour savoir quel programme se plaint
le ">&2" c'est pour envoyer sur STDERR, le canal d'erreur
tu peux mettre aussi ${0##*/} à la place de "$0" pour ne garder que le nom sans le chemin.
Pensez à mettre [Résolu] dans le titre une fois votre problème réglé !
Hors ligne
#10 Le 14/05/2008, à 22:56
- cidou
Re : [resolu][Bash] Divers questions et problèmes sur les scripts-bash
Oui, j'aurais du préciser qu'il s'agit de sujet d'école (ceci est mon brouillon en quelque sorte ), et que je ne le réutiliserais jamais, ce que je fesais pour vérifier ou il avait planté, c'était de voir la variable $? . Mais je suis d'accords que dans un script fait " au propre" ces indications le rende plus lisible et facile d'utilisation
Pour ce qui est des OU_SINON je voulais parler de cette ligne :
elif ! isnum $1 || ! isnum $2 || ! isnum $3 ; then
que j'avais écrite dans une première version comme ceci :
elif ! (isnum $1 || isnum $2 || isnum $3 ); then
Voila, vus que tu t'y connais plutot pas mal en intérprétation shell si tu pouvais me dire ce qui diffère des deux version, ainsi que si il y avait une autre version ayant un résultat identique! thx.
Pourquoi aller voter aux européennes ? ::
http://www.numerama.com/magazine/12948- … u-net.html
Hors ligne
#11 Le 14/05/2008, à 23:28
- snapshot
Re : [resolu][Bash] Divers questions et problèmes sur les scripts-bash
ha ! mais ça, ce n'est pas un problème shell, mais un problème de logique ! Tu ne respectes pas la loi de morgan, à savoir (nonA ou nonB ou nonC) = non(A et B et C)
Donc, si tu veux une seule négation, il faut mettre des &&
elif ! isnum $1 || ! isnum $2 || ! isnum $3 ; then
est équivalent à :
elif ! (isnum $1 && isnum $2 && isnum $3 ); then
Pensez à mettre [Résolu] dans le titre une fois votre problème réglé !
Hors ligne
#12 Le 15/05/2008, à 07:41
- Alain.g
Re : [resolu][Bash] Divers questions et problèmes sur les scripts-bash
Il est également possible d'utiliser les accolades si on ne veut pas que le groupe de commandes soit lancé dans un sous-shell :
if ! { isnum "$1" && isnum "$2" && isnum "$3" ;} ; then
ça peut être utile dans certains cas, par exemple (un peu bidon) :
#!/bin/bash
if {
choix=$(zenity --radiolist --list --column="" --column="programme" \
TRUE "truc" FALSE "bidule") &&
zenity --question --text "$choix va être lancé, doit on continuer ?"
}
then
echo ":-)"
echo lancement de $choix
else
echo ":-("
exit 1
fi
Xubuntu Karmic !
Hors ligne
#13 Le 15/05/2008, à 07:55
- snapshot
Re : [resolu][Bash] Divers questions et problèmes sur les scripts-bash
Exact, un sous-shell = un fork : ça ne parait rien comme ça, mais si il est dans une boucle, alors là, ça devient véritablement pénalisant question temps et ressources.
Par contre, il faut bien faire attention à mettre un « ; » avant la dernière accolade, chose que ne réclament pas les parenthèses, et je n'ai jamais vraiment compris pourquoi
Pensez à mettre [Résolu] dans le titre une fois votre problème réglé !
Hors ligne
#14 Le 15/05/2008, à 16:12
- Alain.g
Re : [resolu][Bash] Divers questions et problèmes sur les scripts-bash
Question temps et ressources, il faut noter aussi que la structure [[ ]] permet de réaliser des tests avec des expressions rationnelles en utilisant l'opérateur =~
Plus rapide que de passer par "echo .. | grep -q"
Exemple en testant un millier d'arguments,
avec grep -q :
#!/bin/bash
function isnum {
until [ -z "$1" ] ; do
echo "$1" | egrep -q '^[-+]?[0-9]+$' && shift || return 1
done
}
if isnum {1..1000}
then echo OK
else echo BAD
fi
avec [[ .. =~ :
#!/bin/bash
function isnum {
until [ -z "$1" ] ; do
[[ "$1" =~ ^[-+]?[0-9]+$ ]] && shift || return 1
done
}
if isnum {1..1000}
then echo OK
else echo BAD
fi
Résultat de time,
Pour le premier avec grep -q :
- real 0m5.936s
- user 0m2.764s
- sys 0m3.124s
Le second avec [[ .. =~:
- real 0m0.161s
- user 0m0.160s
- sys 0m0.000s
Comme on dit, "y'a pas photo"
Attention toutefois aux versions de bash trop anciennes
Dernière modification par Alain.g (Le 15/05/2008, à 16:15)
Xubuntu Karmic !
Hors ligne
#15 Le 15/05/2008, à 21:02
- cidou
Re : [resolu][Bash] Divers questions et problèmes sur les scripts-bash
oula, vous avez poussé un peu loin la :x , deja je ne connais pas l'utilité de zenity ainsi que des options, si vous pouviez m'éclairer dessus !! Ainsi que sur le [[ ]] avec =~ , je n'avais jamais vus cela et je ne comprends pas trop la finalité.
J'ai également quelques autres questions :
je n'arrive pas a faire la différence pour savoir si je dois utiliser la forme $var ou var (var étant une variable bien entendus :x)
-Je m'explique, si j'écris while (( var > 0 )) pourquoi ne puis je pas plutot écrire while (( $var > 0 )) et a lm'inverse si j'écris if (( $var % 2 == 0 )) pourquoi ne puis je pas plutot écrire if (( var % 2 == 0))
Merci de vos précisions !!
Dernière modification par cidou (Le 15/05/2008, à 21:04)
Pourquoi aller voter aux européennes ? ::
http://www.numerama.com/magazine/12948- … u-net.html
Hors ligne
#16 Le 15/05/2008, à 21:14
- snapshot
Re : [resolu][Bash] Divers questions et problèmes sur les scripts-bash
oui, une brillante démonstration !
J'ai fait pareil pour le commentaire #12 avec cet exemple simplifié :
#!/bin/bash
function isnum {
[[ "$1" =~ ^[-+]?[0-9]+$ ]]
}
num=0
alpha=0
for arg in {1..9}{0..9}{0..9}{1,x,2,3,4,x}
do
if ( isnum $arg )
then
(( num++ ))
else
(( alpha++ ))
fi
done
echo num=$num alpha=$alpha
et :
#!/bin/bash
function isnum {
[[ "$1" =~ ^[-+]?[0-9]+$ ]]
}
num=0
alpha=0
for arg in {1..9}{0..9}{0..9}{1,x,2,3,4,x}
do
if { isnum $arg ; }
then
(( num++ ))
else
(( alpha++ ))
fi
done
echo num=$num alpha=$alpha
Pour le premier avec () et donc fork d'un sub-shell :
real 0m7.523s
user 0m2.556s
sys 0m2.408s
et pour le deuxième avec { ;} :
real 0m0.776s
user 0m0.760s
sys 0m0.004s
C'est juste dix fois plus rapide... pour une simple accolade à la place d'une parenthèse ! D'ailleurs, on voit bien l'impact qu'ont les fork sur la charge système.
Le shell, c'est comme SQL, c'est puissant mais si on ne fait pas gaffe à ce que l'on fait, on met à genoux la machine !
Pensez à mettre [Résolu] dans le titre une fois votre problème réglé !
Hors ligne
#17 Le 15/05/2008, à 22:36
- Alain.g
Re : [resolu][Bash] Divers questions et problèmes sur les scripts-bash
ah oui, en effet !
À ce propos je vois très souvent dans les scripts bash "while (true)" et non simplement "while true"
et pourtant :
#!/bin/bash
while (true) ; do (( n++ && n > 10000 )) && break ; done
real 0m17.158s
user 0m6.380s
sys 0m10.597s
alors que
#!/bin/bash
while true ; do (( n++ && n > 10000 )) && break ; done
real 0m0.357s
user 0m0.336s
sys 0m0.016s
"while :" est même un rien plus rapide que "while true"
Cidou, je te conseille de regarder cette page : http://abs.traduc.org/abs-5.3-fr/ch03.html
Tu y trouveras une explication pour les caractères spéciaux qui t'intriguent et des liens vers les chapitres et exemples concernés
Dernière modification par Alain.g (Le 16/05/2008, à 06:08)
Xubuntu Karmic !
Hors ligne
#18 Le 16/05/2008, à 00:24
- cidou
Re : [resolu][Bash] Divers questions et problèmes sur les scripts-bash
Niquel Alain, encore une bonne source d'informations que je vais utiliser grandement
Dernière modification par cidou (Le 16/05/2008, à 14:05)
Pourquoi aller voter aux européennes ? ::
http://www.numerama.com/magazine/12948- … u-net.html
Hors ligne