[RESOLU] Bash : trappage de message

Bash : trappage de message [RESOLU] - Codes et scripts - Linux et OS Alternatifs

Marsh Posté le 30-12-2007 à 03:24:59    

Bonjour,
 
Voilà je dois tester si un paramètre passé à mon script est de type entier. J'avais pensé utiliser typeset (plutôt qu'un bête case "$1" in...), mais j'ai un problème :

Code :
  1. madmox:~/scripts$ typeset -i NB
  2. madmox:~/scripts$ NB="1a" > /dev/null
  3. bash: 1a: valeur trop grande pour la base (error token is "1a" )
  4. madmox:~/scripts$ NB="1a" 2> /dev/null
  5. bash: 1a: valeur trop grande pour la base (error token is "1a" )


Pourquoi la redirection ne marche pas ??? C'est gênant ce message qui s'affiche.
 
Ensuite, autre problème, sûrement lié :

Code :
  1. madmox:~/scripts$ NB="1a" || echo "Erreur"
  2. bash: 1a: valeur trop grande pour la base (error token is "1a" )
  3. madmox:~/scripts$ NB="1a" && echo "Erreur"
  4. bash: 1a: valeur trop grande pour la base (error token is "1a" )
  5. madmox:~/scripts$ NB="1a" ; echo "Erreur"
  6. bash: 1a: valeur trop grande pour la base (error token is "1a" )


Ici, pourquoi le message "Erreur" ne s'affiche pas, et dans aucun cas ? J'ai vérifié le code de retour de NB="1a", c'est 1 (donc bien une erreur), donc s'il est normal que && na marche pas, les deux autres devraient...
 
Edit: Du coup pour le moment j'utilise la ligne :
 
[[ "$ARG" != *[!0-9]* && "$ARG" != "" ]] || traiterErreur
 
Ça marche bien, mais je voudrais comprendre les erreurs du dessus...


Message édité par madmox le 13-01-2008 à 00:05:28

---------------
"Vous êtes un tel connard que je vous inscris pour l'oscar du plus gros connard de l'univers ! Connard !" S.Marsh...
Reply

Marsh Posté le 30-12-2007 à 03:24:59   

Reply

Marsh Posté le 31-12-2007 à 15:34:54    

Je n'en suis pas sur, mais il me semble que typeset renvois un message sur la sortie d'erreur et non sur la sortie normal, ce qui explique pourquoi elle passe à travers le ">".
Comme une erreur est levée, l'instruction s'arrête...
 
Mais ça reste une hypothèse hein :)

Reply

Marsh Posté le 01-01-2008 à 21:30:57    

A priori j'ai indiqué dans mon message précédent que j'avais essayé la redirection de stdout ET stderr ("commande > /dev/null" et "commande 2> /dev/null" )
Donc le problème n'est pas là non ? A moins que j'oublie quelque chose...

Reply

Marsh Posté le 02-01-2008 à 11:49:19    

Et si tu utilisais grep plutôt pour savoir si c'est un entier ?
 
Edit : je viens de voir ton edit
Heu sinon l'affectation c'est pas une commande (un process indépendant). C'est de l'interprétation bash apparemment, donc la redirection de flux ça doit pas trop marcher dessus. C'est le shell bash lui même qu'il faut configurer avec des options.


Message édité par czh le 02-01-2008 à 12:06:22
Reply

Marsh Posté le 02-01-2008 à 12:56:51    

Tout à fais. Celà dit tu peux rediriger le stderr de ton shell avant de lancer la commande, avec un "exec 2>/dev/null". Attention quand même, si tu veux ensuite pouvoir afficher à nouveau stderr, il faut prévoir le coup. Tu peux faire un truc du genre :

exec 3>&2           # On créé le fd 3 pour "sauvegarder" la sortie d'erreur
exec 2>/dev/null    # Maintenant les erreurs ne sont plus affichées
# Tu peux faire tes trucs ici
exec 2>&3           # On restore la sortie d'erreur


Message édité par matafan le 02-01-2008 à 12:59:05
Reply

Marsh Posté le 02-01-2008 à 13:49:26    

Citation :

l'affectation c'est pas une commande (un process indépendant)


Ok... voilà donc l'astuce ! Merci.
 
Pour le coup du

Citation :

exec 3>&2
exec 2>/dev/null
# Tu peux faire tes trucs ici
exec 2>&3


j'essaierai pour voir ça m'a l'air pas mal effectivement. Merci pour l'info.
 
En revanche je n'explique pas vraiment

Code :
  1. # madmox:~/scripts$ NB="1a" ; echo "Erreur"
  2. # bash: 1a: valeur trop grande pour la base (error token is "1a" )


qui n'affiche pas le message "Error", mais je suppose que ça vient encore du même problème (le shell arrete l'éxécution de la ligne à l'erreur d'affectation)


Message édité par madmox le 02-01-2008 à 13:54:44
Reply

Marsh Posté le 06-01-2008 à 20:11:52    

typeset c'est un peu deprecated, ya declare maintenant :  
 
$ help typeset
typeset: typeset [-afFirtx] [-p] name[=value] ...
     Obsolete.  See `declare'.

Reply

Marsh Posté le 11-01-2008 à 15:30:24    

Bash accepte les entiers sous forme "base#nombre", où base est la base de numération. Cette base est par défaut 10 (quand elle est omise).
 
"n=3;" éuivaut à "n=10#3;"
 
Par exemple, "typeset -i n; n=13#4a45; echo $n" donne 10535.
Ca veut dire que le nombre 4a45 sur la base 13 (c'est à dire écrit avec les "chiffres" 0 1 2 3 4 5 6 7 8 9 a b c) vaut 10535 en décimal.
 
Quand tu tapes NR="1a", tu ne précise pas de base, donc c'est 10 par défaut. Or "a" ne fait pas partie des chiffres de la base 10 (qui sont les chiffres de 0 à 9, dix chiffres). C'est pour cela que bash rale. D'ailleurs il se plaint précisément à propos de la "base".
 
Quant au fait de ne pas passer au "echo", je ne vois pas ce qui t'étonnes ! Quand un script rencontre une erreur, il s'arrête, c'est son comportement naturel.  
C'est peut-être que le fait que tu passe les instruction en ligne de commnde qui te perturbes.
Mais si tu mets "echo $(( 1/0 )); ls" dans fichier "err.sh" et que tu tapes "sh (ou bash ou ksh..) err.sh", tu verras jamais le résultat du "ls" ! Seulement l'erreuer résultant du 1/0 (division par 0).
 

Reply

Marsh Posté le 12-01-2008 à 13:42:56    

Citation :

Bash accepte les entiers sous forme "base#nombre", où base est la base de numération. Cette base est par défaut 10 (quand elle est omise).
 
"n=3;" éuivaut à "n=10#3;"
 
Par exemple, "typeset -i n; n=13#4a45; echo $n" donne 10535.
Ca veut dire que le nombre 4a45 sur la base 13 (c'est à dire écrit avec les "chiffres" 0 1 2 3 4 5 6 7 8 9 a b c) vaut 10535 en décimal.
 
Quand tu tapes NR="1a", tu ne précise pas de base, donc c'est 10 par défaut. Or "a" ne fait pas partie des chiffres de la base 10 (qui sont les chiffres de 0 à 9, dix chiffres). C'est pour cela que bash rale. D'ailleurs il se plaint précisément à propos de la "base".

Ca j'avais saisi... le problème c'est pourquoi le echo ne passe pas avec un enchaînement de commande en ";" ou en "||".
 

Citation :

Quand un script rencontre une erreur, il s'arrête, c'est son comportement naturel.

Je crée 2 scripts tests :
 
test_1.sh

Code :
  1. #!/bin/bash
  2. echo $(( 1/0 )) ; ls


test_2.sh

Code :
  1. #!/bin/bash
  2. echo $(( 1/0 ))
  3. ls


L'éxécution du premier s'arrête effectivement à l'erreur (idem avec un "||" à la place du ";" ). C'est ce que je ne comprends pas bien.
En revanche le 2nd affiche le 'ls'. Donc "Quand un script rencontre une erreur, il s'arrête, c'est son comportement naturel" n'est pas vrai (du moins comme je le comprends), mais le fonctionnement de ";" et "||" est différent d'un simple enchaînement de commandes.
 
De plus, si j'éxécute la commande

Code :
  1. ifconfig interface_bidon ; ls

J'ai bien le résultat du ls qui s'affiche, pourtant la première commande lève une erreur (je n'ai pas d'interface qui s'appelle interface_bidon...). Il y a donc une différence entre certaines erreurs.
 
Je pense surtout que le shell arrête l'éxécution d'une ligne lorsqu'il rencontre une erreur du type "echo $(( 1/0 ))" ou "NB="1a"" (cas du NB entier base 10). Mais comment reconnaître une erreur de ce type d'une autre ? (Ce sont d'ailleurs toutes ces erreurs dont on ne peut rediriger la sortie).


Message édité par madmox le 12-01-2008 à 13:46:04
Reply

Marsh Posté le 12-01-2008 à 16:36:05    

Je n'ai pas été très clair sur la deuxième partie apparamment.
 
Sortir ou pas sur erreur, c'est une décision du développeur du programme !
 
Quant tu tapes "ifconfig bidon; ls", t'es dans bash. Il crée (fork) un processus fils où le binaire /bin/ifconfig tourne.
Quand ifconfig rencontre l'erreur due à "bidon", il s'arrête et sort. Il rend la main à son père (bash), qui passe à l'instruction suivante (ls).
Cette sortie est une décision des dévloppeurs de ifconfig, qui ont décidé que s'i l'interfacce désignée n'existait pas, alors "exit -1" ou "return -1"..
 
Reprenons le même raisonnement avec "echo $((1/0)); ls"
 
Avant d'exécuter le "echo $(( 1/0 ))", bash doit évaluer l'expression "$(( 1/0))" qu'il va passer à /usr/bin/echo lorsqu'il le "forkera". Or, les expressions arithmétiques du type "$(())" sont un "built-in" du bash: il ne va pas créer de fils pour évaluer le "$((1/0))", il le fait lui même. Et il rencontre une erreur (division par 0). Alors il affiche un message d'erreur et ne poursuit pas l'évaluation du reste de la ligne. In ne sort pas  (sinon ton promt disparaîtrait) !
Ce comportement est cette fois une décision des développeurs de bash: bash lit les instructions ligne pas ligne et les exécutes de gauche à droite.
Il se moque des erreurs arrivées au sein de ses fils, mais si c'est lui qui se heurte à une erreur, l'exécution de la ligne en cours s'arrête. C'est comme ça que bash fonctionne ! Et c'est pour ça que le fait d'éclater "echo $((1/0)); ls" en une instruction par ligne le fait passer à la ligne suivante. Il arrête l'exécution de la ligne "echo $((1/0))" dès qu'il rencontre une erreur, mais ne sort pas ! Il passe à la ligne suivante "ls".
Heureusement d'ailleurs, parce que s'il sortait suite à ses erreurs, ton terminal disparaîtrait suite au "NB=1a" par exemple !!
 
Dans "ifconfig bidon; ls", il y a erreur, mais ce n'est pas la sienne ! C'est les développeurs de ifconfig qui ont décidé de sortir (de ifconfig !). Ils auraient pu en décider autrement, mais ça aurait été légèrement gênant !
La décision de sortir uniquement sur un "exit" dans bash (et de ne pas sortir sur erreur) est due à la nature d'interpreteur d'nstruction de celui-ci.
C'est juste une (judicieuse !) décision des développeurs.
 
Donc, pour faire simple, quand c'est au shell lui même de faire le boulot (évaluer une expression comme $((1/0)), effectuer une assignation comme NB="1a", ..), si erreur il y a, c'est son problème. Alors il s'arrête (d'interpréter la ligne en cours, et ne sort pas !).
En revanche, si lerreur survient dans l'un de ses "fils" (comme /bin/ifconfig), c'est le problème du fils. C'est le fils qui s'arrête (ou pas d'ailleurs, si le fils est sh par exemple !), et rend la main au bash (ou pas !), qui poursuit jusqu'à la fin de la ligne en cours (tant qu'il-bash- ne recontre pas d'erreur), ou passe à la ligne suivante s'il a atteint la fin de ligne.
 
J'espère avoir été clair cette fois !
 
PS: Les "fils" sont facilement repérables si tu set l'option x (set -x, set +x pour la désactiver) pour déboguer: les lancements de fils  sont précédés d'un signe +.


Message édité par p-seeker23 le 12-01-2008 à 16:40:53
Reply

Marsh Posté le 12-01-2008 à 16:36:05   

Reply

Marsh Posté le 13-01-2008 à 00:04:51    

Bon ben avec une réponse pareil, je peux me coucher maintenant... Nan sérieusement merci d'avoir pris le temps c'était super clair et du coup le sujet est résolu ! J'avais juste pas saisi que le bash évaluait lui-même les expressions (je pensais qu'il faisait un fils dans tous les cas).
Voilà merci encore !

Reply

Marsh Posté le 14-01-2008 à 08:40:24    

Mini précision, pour info ...
 

Citation :

Et c'est pour ça que le fait d'éclater "echo $((1/0)); ls" en une instruction par ligne le fait passer à la ligne suivante. Il arrête l'exécution de la ligne "echo $((1/0))" dès qu'il rencontre une erreur, mais ne sort pas ! Il passe à la ligne suivante "ls".


 
ce comportement peut être changé par la syntaxe

Code :
  1. set -e


en début de script
 
Ainsi, à la moindre erreur (qu'il s'agisse de bash [echo $((1/0))] ou d'une autre commande [ifconfig bidon]), l'exécution du script entier s'arrête

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed