IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Shell et commandes GNU Discussion :

Redirections en ksh


Sujet :

Shell et commandes GNU

  1. #1
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 102
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique en retraite

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 102
    Par défaut Redirections en ksh
    Bonjour,

    J'ai trouvé sur internet comment combiner les redirections et les "pipe tee" pour récupérer séparément la stdout et la stderr d'une commande:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    function mon_test {
        print "sortie_standard"
        print "erreur_standard" 1>&2
    }
    { { mon_test 2>&1 1>&3 | tee TPT_err.txt ; } 3>&1 1>&2 | tee TPT_out.txt ; } > TPT_mix.txt 2>&1
    J'avoue avoir un peu de mal à déchiffrer ce code... mais jusque là, ça va à peu près...

    Peut-on obtenir le même résultat en préfixant et postfixant la commande plutôt qu'en l'encapsulant?

    En gros, j'aimerais pouvoir écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    start_log TPT_out.txt TPT_err.txt TPT_mix.txt
    mon_test
    stop_log
    J'ai fait des recherches et des essais qui sont demeurés jusqu'ici infructueux !

    Est-il nécessaire de passer par des fifos?

    merci d'avance si vous avez des idées!

    )jack(

  2. #2
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    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 : 12 835
    Billets dans le blog
    1
    Par défaut
    Salut

    Le principe du tee est qu'il duplique le flux et envoie une des deux copies vers un fichier. Donc avec tee tu gardes le flux à l'écran et aussi dans le fichier
    Exemple: ls | tee listing.

    Donc si tu veux avoir le flux à l'écran et dans le fichier, tu es obligé de piper ta commande dans un tee ; tu ne peux pas faire sans. C'est comme si tu voulais faire un cat truc |more et que tu demandais "peut-on activer le more en amont?". Ben non, on ne peut pas. Le pipe est justement fait pour associer diverses commandes mais si on veut les associer, il faut quand-même passer par le pipe.

    Sinon je suis impressionné par ton exemple ...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2006
    Messages
    247
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2006
    Messages : 247
    Billets dans le blog
    1
    Par défaut descripteurs ...
    Bonjour
    Vous m'avez l'air tous les deux initiés a leur fonctionnement :

    descripteur 3

    pourriez vous expliciter l'ordre de prise en compte des redirections de l'exemple de jack-ft ?

    Par exemple , que se passerait il si on inversait l'ordre de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    mon_test 2>&1 1>&3 pour faire
    mon_test 1>&3 2>&1
    ou que l'on jouait avec des (sous-shell) au lieu des {} ?

    Je comprends que les descripteurs 0 1 et 2 soient "reservés" mais quid du 3 ou autre choix ? ne peut il pas etre deja "reservé/occupé" ?

    sous ksh j'ai souvent utilisé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     # Redirection de la log
      print DEBUT TRAITEMENT >${F_LOG}
      exec 2>>${F_LOG}
      exec 1>>${F_LOG}
    le fichier doit etre créé avant les redirections.
    Est ce bien car c'est seulement quand il est créé qu'il a un descripteur associé ? peut on savoir a quel descripteur il est associé ?
    D'autre part il me semble que lors de long traitement sans ecriture, le redirection se "perdait".
    Y a t'il des mecanismes qui "ferment" les descripteurs apres un certain temps d'inactivité ?

    Merci d'avance de vos reponses.

  4. #4
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 102
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique en retraite

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 102
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Salut

    Le principe du tee est qu'il duplique le flux et envoie une des deux copies vers un fichier. Donc avec tee tu gardes le flux à l'écran et aussi dans le fichier
    Exemple: ls | tee listing.
    Merci d'avoir répondu et merci pour l'emploi de la balise "codeinline"!
    Je sens que ça va me resservir!

    Sinon je suis impressionné par ton exemple ...
    Euh... je te rappelle qu'il n'est pas de moi! (juste pour que ce soit bien clair!)
    Je ne suis pas assez musclé en shell pour pondre ça

    Donc si tu veux avoir le flux à l'écran et dans le fichier, tu es obligé de piper ta commande dans un tee ; tu ne peux pas faire sans. C'est comme si tu voulais faire un cat truc | more et que tu demandais "peut-on activer le more en amont?". Ben non, on ne peut pas.
    Le pipe est justement fait pour associer diverses commandes mais si on veut les associer, il faut quand même passer par le pipe.
    Ben justement, si, on peut!
    Je suis un peu désolé de te contredire... surtout que je ne sais pas bien comment faire!!!
    Mais ce que j'ai vu par ailleurs me confirme dans cette certitude!
    Maintenant, si tu me dis qu'on ne peut pas sans fifo (ce qui était ma question originelle), je veux bien l'admettre humblement!
    Voici un embryon de solution:
    http://stackoverflow.com/questions/3173131/redirect-copy-of-stdout-to-log-file-from-within-bash-script-itself
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    PIPE=tmp.fifo
    mkfifo $PIPE
    exec >$PIPE
    tee foo.log <$PIPE &
     
    # rest of your script
     
    rm $PIPE
    ou bien, vu sur http://stackoverflow.com/questions/2...iple-files-tee
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
       OUTPUT_LOG=output.log
      OUTPUT_PIPE=output.pipe
     
      rm -f $OUTPUT_PIPE
      mkfifo $OUTPUT_PIPE
      rm -f $OUTPUT_LOG
     
      tee $OUTPUT_LOG < $OUTPUT_PIPE &
      tpid=$!
     
      exec 3>&1 4>&2 >$OUTPUT_PIPE 2>&1
     
      echo "This is on standard out"
      echo "This is on standard err" >&2
     
      exec 1>&3 3>&- 2>&4 4>&-
      wait $tpid
      rm -f $OUTPUT_PIPE
    Quelqu'un verrait-il comment transformer ces exemples pour répondre à ma question: un tee pour la stdout, un tee pour la stderr, un tee pour les 2 ?
    Merci d'avance
    )jack(

  5. #5
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    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 : 12 835
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Jean.Cri1 Voir le message
    pourriez vous expliciter l'ordre de prise en compte des redirections de l'exemple de jack-ft ?

    Par exemple , que se passerait il si on inversait l'ordre de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    mon_test 2>&1 1>&3 pour faire
    mon_test 1>&3 2>&1
    ou que l'on jouait avec des (sous-shell) au lieu des {} ?
    Ben pourquoi tu n'as pas essayé ?
    Donc moi j'ai essayé. Il semblerait que les redirections soient prises depuis la fin. Donc dans mon_test 2>&1 1>&3 le descripteur 1 est d'abord redirigé vers le 3 avant que le 2 soit redirigé vers le 1

    Citation Envoyé par Jean.Cri1 Voir le message
    Je comprends que les descripteurs 0 1 et 2 soient "reservés" mais quid du 3 ou autre choix ? ne peut il pas etre deja "reservé/occupé" ?
    Non puisque le shell est exécuté dans un processus "neuf" dans lequel les descripteur de 3 à 64 sont dispos...

    Citation Envoyé par Jean.Cri1 Voir le message
    D'autre part il me semble que lors de long traitement sans ecriture, le redirection se "perdait".
    Y a t'il des mecanismes qui "ferment" les descripteurs apres un certain temps d'inactivité ?
    ???


    Citation Envoyé par jack-ft Voir le message
    Merci d'avoir répondu et merci pour l'emploi de la balise "codeinline"!
    Je sens que ça va me resservir!
    Il faut toutefois impérativement mettre au-moins un caractère après la balise fermante sinon les retour à la ligne ne sont pas pris en compte.

    Citation Envoyé par jack-ft Voir le message
    Ben justement, si, on peut!
    Je suis un peu désolé de te contredire...
    Bah, c'est ça l'avantage des forums... on apprend les uns des autres...

    Citation Envoyé par jack-ft Voir le message
    surtout que je ne sais pas bien comment faire!!!
    Mais ce que j'ai vu par ailleurs me confirme dans cette certitude!
    Maintenant, si tu me dis qu'on ne peut pas sans fifo (ce qui était ma question originelle), je veux bien l'admettre humblement!
    Voici un embryon de solution:
    http://stackoverflow.com/questions/3173131/redirect-copy-of-stdout-to-log-file-from-within-bash-script-itself
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    PIPE=tmp.fifo
    mkfifo $PIPE
    exec >$PIPE
    tee foo.log <$PIPE &
     
    # rest of your script
     
    rm $PIPE
    ou bien, vu sur http://stackoverflow.com/questions/2...iple-files-tee
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
       OUTPUT_LOG=output.log
      OUTPUT_PIPE=output.pipe
     
      rm -f $OUTPUT_PIPE
      mkfifo $OUTPUT_PIPE
      rm -f $OUTPUT_LOG
     
      tee $OUTPUT_LOG < $OUTPUT_PIPE &
      tpid=$!
     
      exec 3>&1 4>&2 >$OUTPUT_PIPE 2>&1
     
      echo "This is on standard out"
      echo "This is on standard err" >&2
     
      exec 1>&3 3>&- 2>&4 4>&-
      wait $tpid
      rm -f $OUTPUT_PIPE
    Oui j'avais pensé aussi à passer par exec mais j'ai abandonné car ça ne marche pas. Parce que tes exemples ne sont en fait que des connexions à travers des pipes (ici fichiers pipes et non pipes mémoires) mais toujours pipes...
    Ton premier exemple ne fonctionne pas (chez-moi ou alors je l'ai mal recopié). Et ton 2° exemple ne correspond quand-même pas à ta demande initiale qui était (comme je l'ai comprise)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    start_log # sous-entendu "début de mise en log"
    commande # sous-entendu "tout ce qui en sort est loggué
    stop_log # sous-entendu "fin de mise en log"
    Citation Envoyé par jack-ft Voir le message
    Quelqu'un verrait-il comment transformer ces exemples pour répondre à ma question: un tee pour la stdout, un tee pour la stderr, un tee pour les 2 ?
    Merci d'avance
    Ton exemple initial le fait déjà. Mais ne te permet pas de faire un "départ log" puis un "arrêt log".

    Toutefois j'ai utilisé ton premier exemple pour écrire ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #!/bin/sh
     
    log_commande() {
    	file_out="$1"
    	file_err="$2"
    	file_all="$3"
    	cde="$4"
    	shift 4
    	{ { "$cde" $* 2>&1 1>&3 | tee "$file_err" ; } 3>&1 1>&2 | tee "$file_out" ; } > "$file_all" 2>&1
    }
     
    log_commande ls.out ls.err ls.all ls -l /etc/passwd /etc/group xxx
    log_commande who.out who.err who.all who
    Et si tu remplaces la dernière ligne de la fonction par
    { { "$cde" $* 2>&1 1>&3 | tee "$file_err" ; } 3>&1 1>&2 | tee "$file_out" ; } 2>&1 | tee "$file_all" (une petite subtilité sur le dernier tee) alors la commande exécutée va à la fois dans le fichier final et à la fois à l'écran.

    Donc cela pourrait peut-être faire l'affaire...?
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  6. #6
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 102
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique en retraite

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 102
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Ton premier exemple ne fonctionne pas (chez-moi ou alors je l'ai mal recopié).
    Euh... chez moi non plus, il ne marche pas... et j'avoue ne pas être allé plus loin...

    Et ton 2° exemple ne correspond quand-même pas à ta demande initiale qui était (comme je l'ai comprise)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    start_log # sous-entendu "début de mise en log"
    commande # sous-entendu "tout ce qui en sort est loggué
    stop_log # sous-entendu "fin de mise en log"
    Euh... voui, tu as bien compris ma demande initiale et, voui aussi, mon 2ème exemple correspond bien (partiellement) à ma demande! je suis un peu perplexe... quant au mismatch!
    Est-ce à cause des lignes
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    echo "This is on standard out"
    echo "This is on standard err" >&2
    qui donnent juste un exemple d'une commande fournissant quelque chose (de facilement prédictible) sur la stdout et la stderr?

    Ton exemple initial le fait déjà. Mais ne te permet pas de faire un "départ log" puis un "arrêt log".

    Toutefois j'ai utilisé ton premier exemple pour écrire ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #!/bin/sh
     
    log_commande() {
    	file_out="$1"
    	file_err="$2"
    	file_all="$3"
    	cde="$4"
    	shift 4
    	{ { "$cde" $* 2>&1 1>&3 | tee "$file_err" ; } 3>&1 1>&2 | tee "$file_out" ; } > "$file_all" 2>&1
    }
     
    log_commande ls.out ls.err ls.all ls -l /etc/passwd /etc/group xxx
    log_commande who.out who.err who.all who
    Et si tu remplaces la dernière ligne de la fonction par
    { { "$cde" $* 2>&1 1>&3 | tee "$file_err" ; } 3>&1 1>&2 | tee "$file_out" ; } 2>&1 | tee "$file_all" (une petite subtilité sur le dernier tee) alors la commande exécutée va à la fois dans le fichier final et à la fois à l'écran.

    Donc cela pourrait peut-être faire l'affaire...?
    Je garde cette proposition sous le coude...

    Juste une petite remarque sur ton code (au cas où ça pourrait servir): le traitement des arguments est une vraie plaie en shell script (en comparaison de langages plus "évolués" (ou à syntaxe mieux élaborée)). la partie "$cde" $* ne gère pas correctement le cas où les arguments contiennent des espaces, comme, par exemple, grep 'syntax error' *.log.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #!/bin/sh
     
    log_commande() {
    	file_out="$1"
    	file_err="$2"
    	file_all="$3"
    	cde="$4"
    	shift 4
    	{ { "$cde" $* 2>&1 1>&3 | tee "$file_err" ; } 3>&1 1>&2 | tee "$file_out" ; } 2>&1 | tee "$file_all"
    }
     
    echo "syntax error" > foose
    echo syntax > foos
    echo "no syntax error" > 'foo with space'
     
    if [[ -d log ]] ; then rm -f log/* ; else mkdir log ; fi
     
    log_commande log/ls.out log/ls.err log/ls.all fgrep 'syntax error' *
    =>                                                                                              
    fgrep: error: No such file or directory
    fgrep: foo: No such file or directory
    fgrep: with: No such file or directory
    fgrep: space: No such file or directory
    foos:syntax
    foose:syntax error

    De manière générale, je ne me souviens pas avoir vu de cas où l'utilisation de $* ne puisse être avantageusement remplacée par "$@".

    Oops! Double négation! Je rectifie: on peut/doit toujours remplacer $* par "$@". (Si quelqu'un a un contre-exemple, je suis preneur (pour ma culture)!)

    Cependant, le $cde $* et le $cde "$@" provoquent une erreur lorsque la commande à tracer n'a aucun argument et que l'option "nounset" est positionnée soir par set -u, par set -o nounset ou comme argument du shell ksh -u script.

    Du coup, il vaudrait mieux shifter un argument de moins (4 étant de toute façon le minimum requis) ce qui donne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #!/bin/sh
     
    log_commande() {
    	file_out="$1"
    	file_err="$2"
    	file_all="$3"
    	shift 3
     
    	{ { "$@" 2>&1 1>&3 | tee "$file_err" ; } 3>&1 1>&2 | tee "$file_out" ; } 2>&1 | tee "$file_all"
    }
     
    log_commande log/ls.out log/ls.err log/ls.all fgrep 'syntax error' * 
    foo with space:no syntax error
    foose:syntax error
    En ce qui concerne mes recherches, en fait, j'ai repris le 2ème exemple et fait pour stderr la même chose que pour stdin et ça marche! Joie! Voici le code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    function _TPT_out_and_err {
        # The command which writes sth on stdin and sth else on stderr
        print "${_TPT_OUT_STRING}"
        print "${_TPT_ERR_STRING}" 1>&2
    }
     
    test_TPT_ok_06() {
        print "Test: test_TPT_ok_06"
     
        # Start logging
        rm -f ${_TPT_OUT_PIPE}
        mkfifo ${_TPT_OUT_PIPE}
        rm -f ${_TPT_OUT_FILE}
     
        tee ${_TPT_OUT_FILE} < ${_TPT_OUT_PIPE} &
        typeset top_pid=$!
     
        rm -f ${_TPT_ERR_PIPE}
        mkfifo ${_TPT_ERR_PIPE}
        rm -f ${_TPT_ERR_FILE}
     
        tee ${_TPT_ERR_FILE} < ${_TPT_ERR_PIPE} &
        typeset tep_pid=$!
     
        exec 3>&1 4>&2 > ${_TPT_OUT_PIPE} 2> ${_TPT_ERR_PIPE}
     
        # The command which writes sth on stdin and sth else on stderr
         _TPT_out_and_err
     
        # Stop logging
        exec 1>&3 3>&- 2>&4 4>&-
        wait $top_pid
        rm -f ${_TPT_OUT_PIPE}
     
        wait $tep_pid
        rm -f ${_TPT_ERR_PIPE}
     
        # Unit test to check the expected contents of stdout and stderr
        typeset _tpt_out_str=$(cat "${_TPT_OUT_FILE}")
        typeset _tpt_err_str=$(cat "${_TPT_ERR_FILE}")
     
        [[ "${_tpt_out_str}" = "${_TPT_OUT_STRING}" ]] \
            || print "FAILED out"
     
        [[ "${_tpt_err_str}" = "${_TPT_ERR_STRING}" ]] \
            || print "FAILED err"
    }
    Voilou!

    )jack(

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. KSH redirection de substitution de processus
    Par N_BaH dans le forum Shell et commandes GNU
    Réponses: 5
    Dernier message: 28/09/2012, 14h04
  2. Réponses: 0
    Dernier message: 13/03/2008, 10h10
  3. [VB.NET]Double redirection.
    Par CammCamm dans le forum ASP.NET
    Réponses: 9
    Dernier message: 24/11/2003, 15h11
  4. [VB6] probleme de redirection d'une commande DOS
    Par WriteLN dans le forum VB 6 et antérieur
    Réponses: 6
    Dernier message: 10/06/2003, 09h36
  5. [reseaux] redirection de flux
    Par Olive1808 dans le forum Programmation et administration système
    Réponses: 2
    Dernier message: 12/08/2002, 09h24

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo