Contenu | Rechercher | Menus

Annonce

Si vous rencontrez des soucis à rester connecté sur le forum (ou si vous avez perdu votre mot de passe) déconnectez-vous et reconnectez-vous depuis cette page, en cochant la case "Me connecter automatiquement lors de mes prochaines visites".
Test de l'ISO d'Ubuntu francophone : nous avons besoin de testeurs pour la version francophone d'Ubuntu 14.04. Liens et informations ici.

Attention, une faille de sécurité dans bash a récemment été rapportée, il est recommandé de mettre à jour son système (plus de détails) *** mise à jour 12/10/2014 ***

#26 Le 14/11/2009, à 00:13

FRUiT

Re : [RESOLU] exec, bashrc, redirections permanentes

Bonjour Totor smile

Pardonne moi d'avoir mis du temps à te répondre, il a fallu que j'étudie de très près ta solution. De mon coté j'ai bien étudié également et suis arrivé à un résultat plutôt satisfaisant. Chacune des 2 méthodes présente un certain nombre d'avantages et d'inconvénients que je vais tenter d'expliquer au mieux.

La méthode Totor

 
 
function traceErreurs()
{
  logFile="$1"
  while read -u 4 LIGNE
  do
   [ "${LIGNE}" = "END" ] && break;
   [ Traitement spécifique de ton erreur ]
  done
}

mkfifo /tmp/$$.pipe
exec 4<>/tmp/$$.pipe
traceErreurs ~/$$.log &

exec 3>&2
PROMPT_COMMAND='exec 2>&3'
trap 'exec 2>&4' DEBUG


et dans le fichier ~/.bash_logout, rajoute ceci :


echo "END" >&4
rm -f /tmp/$$.pipe

Les plus
- Solution "propre" (en tout cas comparé à la mienne)
- Exécute une seule fois toute commande
- Permet de loguer dans un fichier, eventuellement formatté sous forme de sessions
- Donne tout le contenu de stderr (notemment les "command hints")

Les moins
- Utilse 2 fd supplémentaires (fd3 et fd4) ainsi que mkfifo et au moins un fichier sur le disque
- Le résultat est un flux sous forme de "lignes" et non sous forme de "messages d'erreur"
- Le formattage (espaces tabulations) des messages d'erreur est parfois perdu (exemple commande 'sed' sans argument)
- L'ordre des flux stderr et stdout n'est plus respecté (mélange entre les 2)

La méthode FRUiT

 
 
# Enable DEBUG trap
set -o functrace
shopt -s extdebug

PROMPT_COMMAND='
  ENUM=$?
  LCMD="$(history 1 | sed -e "s/^[ ]*[0-9]*[ ]*//g")"
  history -a; history -r
  if [ $ENUM -ne 0 ]; then
    EMSG=$( bash -c "${LCMD} 2>&1 >/dev/null" )
    # Code à compléter exemple : envoyer la variable dans un script :
    # msgd -m fail "\033[31m$EMSG\033[0m" "\033[31m"
    # msgd -e "Error $ENUM"
  else
    # Commande réussie
    echo "${LCMD}" >> /home/fruit/misc/knowledge/global_history
  fi
  # La DERNIERE ! instruction de la variable PROMPT_COMMAND
  exec 2>&4
'

# Les deux DERNIERES ! lignes de bashrc
exec 4>&2
trap 'exec 2>/dev/null' DEBUG

Les plus
- N'utilise qu'un seul fd supplémentaire
- N'utilise pas mkfifo et donc pas de nouveau fichier utilisant le disque
- N'utilise pas '~/.bash_logout' ou son équivalent
- Le résultat est une variable en mémoire contenant le message d'erreur entier
- Le formattage des messages d'erreurs est conservé, mếme en envoyant dans un script annexe
- L'ordre des flux stderr et stdout n'est pas respecté MAIS les flux ne sont pas mélangés

Les moins
- Exécute une 2eme fois toute commande ayant provoqué une erreur (possibilités de ralentissement sur de grosses commandes)
- Lance un sous-shell pour chaque erreur
- N'affiche pas les "command hints"


Notes
Dans  ce cas précis je préfère travailler avec des variables (plus maléables et "expansables") qu'avec des fichiers.

En fait le traitement 'par lignes' est idéal dès lors qu'il s'agit simplement de colorer les messages d'erreurs. Lorsque les manipulations sont plus complexes cela se gâte un peu, car il devient compliqué de récupérer le message d'erreur entier. Exemple je veux envoyer le résultat à un script de traitement, il devient plus commode (même obligatoire) d'envoyer l'erreur entièrement et non envoyer chaque ligne au script.

En fait de ces deux pistes, la mienne 'semble' me convenir mieux (je reposterai mes impressions après avoir longuement testé chaque méthode) bien que la piste de Totor me semble d'emblée beaucoup plus propre. Il n'en reste pas moins que les deux pistes fonctionnent parfaitement. Pour tout dire je pensais courrir après une chimère, mais finalement ça se met en oeuvre assez facilement.

Un très très très grand mega merci à toi Totor ! d'avoir pris du temps pour étudier cette question, pour avoir trouvé une solution, et pour tout le reste smile

Dernière modification par FRUiT (Le 15/11/2009, à 15:18)


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

Hors ligne

#27 Le 14/11/2009, à 09:50

Totor

Re : [RESOLU] exec, bashrc, redirections permanentes

Bonjour,

FRUiT a écrit :

Un très très très grand mega merci à toi Totor ! d'avoir pris du temps pour étudier cette question, pour avoir trouvé une solution, et pour tout le reste smile

You're wellcome !


Ta méthode est astucieuse. Je crains toutefois que tu aies quelques propblèmes de lenteur. Surtout si la commande source de l'erreur est issue d'un traitement très long (ex. traitement video wink) Sans compter sur la manipulation de l'historique à chaque instruction (minime je pense selon la taille autorisée, mais tout de même) !
Par ailleurs, il se peut que ce ne soit pas fiable : supposons qu'une erreur ait pour origine une mauvaise valeur d'une variable d'environnement. Or, puisque tu lances bash en mode non intéractif, le bashrc ne sera pas chargé. les variables d'environnement ne sont donc pas chargées. De toute façon, puisque tu lances une instance de bash, le contexte reste totalement différent, il se peut donc que tu n'obtiennes pas le même résultat.


A noter qu'en te relisant, j'ai trouvé une erreur dans mon script :
remplacer trap 'exec 2>&4 DEBUG' par trap 'exec 2>&4' DEBUG

FRUiT a écrit :

- Le résultat est un flux sous forme de "lignes" et non sous forme de "messages d'erreur"

En utilisant le principe que tu utilises de gestion de l'historique, on doit pouvoir remédier à cela (sauf pour "les command hint").

FRUiT a écrit :

- Le formattage (espaces tabulations) des messages d'erreur est parfois perdu (exemple commande 'sed' sans argument)

étonnant ?
as-tu déterminer à quel moment le formatage est perdu ?
as-tu essayé un echo -e ?

FRUiT a écrit :

- L'ordre des flux stderr et stdout n'est pas respecté MAIS les flux ne sont pas mélangés

peux-tu préciser car je ne vois pas où tu gères la sortie standard et l'intérêt ?

Dernière modification par Totor (Le 14/11/2009, à 09:50)


-- Lucid Lynx --

Hors ligne

#28 Le 15/11/2009, à 16:09

FRUiT

Re : [RESOLU] exec, bashrc, redirections permanentes

Totor a écrit :

Bonjour,

FRUiT a écrit :

Un très très très grand mega merci à toi Totor ! d'avoir pris du temps pour étudier cette question, pour avoir trouvé une solution, et pour tout le reste smile

You're wellcome !


Ta méthode est astucieuse. Je crains toutefois que tu aies quelques propblèmes de lenteur. Surtout si la commande source de l'erreur est issue d'un traitement très long (ex. traitement video wink)

En réfléchissant très dur au problème je pense que dans l'ensemble mis à part une ou 2 commandes vraiment spécifiques ça devrait fonctionner pas mal. L'exemple que tu proposes est d'ailleurs excellent.
Il faut clairement distinguer le type d'erreur à laquelle on a à faire.
1) Erreur de syntaxe, de formulation, de paramètres, fichier absent etc.
Dans ce cas la commande s'exécute mais s'arrète aussitôt, pour délivrer le message d'erreur, et le processus (exemple traitement video) ne démarre pas ! exécuter une 2ème fois la commande ne retarde que de très peu l'apparition du prompt suivant.

2) La commande est bonne et le processus démarre
Dans ton exemple de traitement video, si le processus est engagé, c'est que la commande a réussi. Et donc les erreurs qui pourraient éventuellement être générées pendant ce processus sont généralement gérées pendant et par celui ci. Dans un tel cas la commande ne s'exécutera donc pas 2 fois.

Globalement je n'ai pas encore trouvé de commande générant une erreur qui soit longue au point que ma méthode serait inacceptable. Ceci dit tu as raison et c'est ce à quoi je faisais allusion par "ce n'est pas très propre comme méthode". c'est la raison pour laquelle je disais dans mon précédent message que je dois encore aprofondir et tester de plus belle.

Totor a écrit :

Sans compter sur la manipulation de l'historique à chaque instruction (minime je pense selon la taille autorisée, mais tout de même) !

Ca je l'avais déjà bien avant de commencer mes redirections de stderr. J'ai mis 20000 entrées comme option dans mon bashrc pour l'historique (mais je pense que c'est bien au delà du max j'ai pas vérifié) et ce petit processus de log est instantané et invisible, même sur un eeepc 901 pas vraiment super véloce.

Totor a écrit :

Par ailleurs, il se peut que ce ne soit pas fiable : supposons qu'une erreur ait pour origine une mauvaise valeur d'une variable d'environnement. Or, puisque tu lances bash en mode non intéractif, le bashrc ne sera pas chargé. les variables d'environnement ne sont donc pas chargées. De toute façon, puisque tu lances une instance de bash, le contexte reste totalement différent, il se peut donc que tu n'obtiennes pas le même résultat.

Ca c'est tout à fait exact et bien que j'ai pas non plus rencontré d'exemples jusque là non plus, je m'y attends. Je posterai des retours plus tard quand j'aurai testé un mois ou deux.

Totor a écrit :

A noter qu'en te relisant, j'ai trouvé une erreur dans mon script :
remplacer trap 'exec 2>&4 DEBUG' par trap 'exec 2>&4' DEBUG

J'ai corrigé également dans mon post, histoire de ne pas prèter à confusion pour d'éventuels lecteurs.

Totor a écrit :
FRUiT a écrit :

- Le résultat est un flux sous forme de "lignes" et non sous forme de "messages d'erreur"

En utilisant le principe que tu utilises de gestion de l'historique, on doit pouvoir remédier à cela (sauf pour "les command hint").

Je n'ai pas testé vraiment à fond mais j'ai eu des difficultés à rassembler ces 'lignes' dans un seul message global. Le problème étant à mon avis que ta fonction lit un 'flux' (venant du fifo) et non le résultat précis d'une commande en particulier.

Totor a écrit :
FRUiT a écrit :

- Le formattage (espaces tabulations) des messages d'erreur est parfois perdu (exemple commande 'sed' sans argument)

étonnant ?
as-tu déterminer à quel moment le formatage est perdu ?
as-tu essayé un echo -e ?

J'ai essayé 'echo -e' effectivement, d'ailleurs ne serait-ce que pour colorer en rouge c'est un peu obligatoire.
Sur la commande 'sed' sans argument les tabulations pour distinguer les options de leur description sont perdues je ne sais pas vraiment pourquoi. La même commande avec ma méthode (qui envoie pourtant le texte dans un autre script, qui se termine bien sur également par un 'echo -e') et là, les tabulations sont respectées...
Pourtant, ta méthode respecte le formatage sur d'autres commandes... Peut-être est-ce simplement une histoire de guillemets je tenterai également d'approfondir.

Totor a écrit :
FRUiT a écrit :

- L'ordre des flux stderr et stdout n'est pas respecté MAIS les flux ne sont pas mélangés

peux-tu préciser car je ne vois pas où tu gères la sortie standard et l'intérêt ?

Alors je me suis mal exprimé encore une fois big_smile
Certains programmes envoient une partie de l'erreur sur stderr, et affichent directement eux même une autre partie. Exemple : la commande 'sudo aptitude giant-upgrade' provoque une erreur. Admettons que nous colorons en rouge stderr. Une partie du message sera affichée de la couleur par défaut, et une petite partie seulement (une ligne en fait : 'Commande inconnue « giant-upgrade » ') transitera dans sdterr et sera affichée en rouge.

Avec ta méthode, cette partie rouge peut se retrouver aléatoirement au début, au milieu, ou à la fin du message dans sa globalité. La commande exemple n'a qu'une ligne rouge parmi un texte de la couleur par défaut, ce n'est pas grave. Si c'étaient 10 lignes rouges et dix lignes normales, ce serait déjà plus ennuyeux bien que le cas est surement rare.

Avec ma méthode, ces deux 'parties' du message, sont affichées l'une apres l'autre, et toujours le rouge en 2eme. (puisqu'une partie provient de la commande exécutée en premier, et l'autre de la commande exécutée une seconde fois dans PROMPT_COMMAND).

En fait je ne 'gère' pas la sortie standard dans ma fonction 'PROMPT_COMMAND', elle s'affiche d'elle même une fois la commande lancée.

Et les flux ne sont pas respectés non plus par ma méthode car stderr s'affichera toujours et obligatoirement en 2eme (cet aspect m'arrange aussi fortement). Dans la commande exemple ('sudo aptitude giant-upgrade'), en temps normal (sans redirections) le message d'erreur s'affiche en premier ('Commande inconnue « upgrrrrrade » '), puis le reste du texte alors qu'avec ma méthode cet ordre n'est plus respecté. Cela doit dépendre des commandes.

J'espère avoir été clair hmm


En fait pour le moment je vais passer un certain temps avec ma méthode, observer et noter ce qui se passe au fil des mes utilisations, je ferai ensuite de même avec ta méthode. Dans tout les cas je note précieusement ce petit code magique que tu m'as grâcieusement offert !! smile smile smile

Encore marci smile

Dernière modification par FRUiT (Le 16/11/2009, à 14:57)


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

Hors ligne

Haut de page ↑