Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#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 2


elif !  isnum $1  || ! isnum $2 || !  isnum $3 ; then
#ma meme version (fausse de la ligne ci-dessus)
#elif ! (isnum $1 || isnum $2 || isnum $3 ); then

    exit 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 ] ; then

    echo "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 tongue

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!! smile

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 ! tongue (ca y va creshendo tongue)

ps : *snapshot : dit moi ce qu'il te parrait douteux stp smile

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 tongue, 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 hmm

Je vais donc garder la notation (( *liste* )) qui me semble la plus_mieux !! smile

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 tongue.
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 wink

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. smile


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" big_smile

Attention toutefois aux versions de bash trop anciennes wink

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 !! smile 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

roll

"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 smile

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