Forum Programmation.shell Execution background et code de sortie

Posté par  .
Étiquettes : aucune
0
30
juin
2005
Bonjour,

dans un script je fais tourner en parallèle plusieurs commandes.
Je reprend la main après un wait.

Ma question, comment savoir que l'ensemble (ou chacune) de mes commandes s'est bien déroulée?
$? ne me donne le statut de sortie que de la dernière.
Et quand j'essais de les mettre dans des accolades, le shell me dit que le ; n'est pas attendu...

Mon script actuel:


#!/bin/ksh
commande1 "$var1" SUPERIEUR fichier1 &
commande2 "$var2" SUPERIEUR fichier2 &
commande3 "$var3" SUPERIEUR fichier3 &
wait

echo "Statut = $?"


Ca me donne le code de sortie de commande3


{ commande1 "$var1" SUPERIEUR fichier1 & ; commande2 "$var2" SUPERIEUR fichier2 & ; ... }


ne marche pas, j'obtient: `;' unexpected

Merci d'avance

PS: Je suis sous SunOS / ksh
SUPERIEUR = le symbole supérieur (j'arrive pas a l'afficher dans le forum)
  • # Solution non testée....

    Posté par  . Évalué à 2.

    { commande1 > fichier1 && CODE1 = $? } &
    { commande2 > fichier2 && CODE2 = $? } &
    { commande3 > fichier3 && CODE3 = $? } &
    wait
    echo La commande1 a eu pour code de retour $CODE1
    echo La commande2 a eu pour code de retour $CODE2
    echo La commande3 a eu pour code de retour $CODE3

    Comme dit en titre, je n'ai pas testé, mais ça devrait marcher, non ?
    • [^] # Re: Solution non testée....

      Posté par  . Évalué à 4.

      M@#!?# ! J'ai oublié de préciser : pour avoir les signes cabalistiques sur linuxfr, utilise les entités html ("& g t ;" pour supérieur, sans les espaces, "& l t" ; pour infiérieur, "& e u r o ;" pour le symbole € etc.).
    • [^] # Re: Solution non testée....

      Posté par  . Évalué à 1.

      ...

      oui, ca devrait et le pire est que c'est super simple...

      Merci beaucoup!
      • [^] # ... malheureusement

        Posté par  . Évalué à 2.

        Salut,

        Je ne pense pas que cela puisse fonctionner en l'état :
        - le "&&" qui sépare la commande de l'affectation de la variable CODEx fait que cette affectation ne sera effectuée que si la commande sort sans erreur. Donc, soit CODEx vaut 0, soit elle n'existe pas du tout. On pourrait remplacer && par un simple ; (point virgule), mais ...
        - lorsque des commande sont exécutées en arrière plan, il y a un fork du shell. Tout ce qui est entre accolades est donc exécuté par un sous shell, et aucune des variables affectées dans ce sous-shell n'est récupérable par le shell appelant. Après le wait, les variables CODEx n'existent donc pas (sauf si elles avaient été déclarées avant, mais alors leur valeur ne serait pas modifiée).


        La réponse au problème semble effectivement plus complexe que prévue.

        Quelques pistes à explorer :
        - wait sans argument attend que tous les processus fils soient terminés (et renvoie certainement le code retour du dernier qui se finit)
        - on peut récupérer le PID d'un process lancé en arrière plan dans la variable $!
        - wait nnn attend la fin du process ayant le pid nnn (mais je ne vois pas bien comment utiliser wait ici, pour attendre la fin de plusieurs processus successivement alors que l'on ne connaît pas l'ordre dans lequel ils vont finir)

        Une solution simple (même si elle n'est pas très élégante) pourrait être de rajouter, à la fin des commandex quelque chose du genre "echo $? > /tmp/$$", de récupérer dans une variable le pid des commande en background ($!) et de relire les fichiers concernés après le wait.
        En plus clair :


        { commande1 "$var1" > fichier1 ; echo $? >/tmp/res.$$ ; } &
        pid1=$!
        { commande2 "$var2" > fichier2 ; echo $? >/tmp/res.$$ ; } &
        pid2=$!
        { commande3 "$var3" > fichier3 ; echo $? >/tmp/res.$$ ; } &
        pid3=$!

        wait
        retour1=`cat /tmp/res.$pid1`
        rm /tmp/res.$pid1
        retour2=`cat /tmp/res.$pid2`
        rm /tmp/res.$pid2
        retour3=`cat /tmp/res.$pid3`
        rm /tmp/res.$pid3
        • [^] # Re: ... malheureusement

          Posté par  . Évalué à 1.

          Tout ceci est très pertinent, mais m'amène à penser la chose suivante :
          plutôt que d'utiliser des fichiers temporaires, pourquoi ne pas utiliser la commande export pour positionner les variables de code de retour une bonne fois pour toutes ?
          Ce qui reviendrait à :
          { commande1 > fichier1 && export CODE1 = $? } &
          { commande2 > fichier2 && export CODE2 = $? } &
          { commande3 > fichier3 && export CODE3 = $? } &
          wait
          echo La commande1 a eu pour code de retour $CODE1
          echo La commande2 a eu pour code de retour $CODE2
          echo La commande3 a eu pour code de retour $CODE3

          Si jamais on veut faire propre, il suffit de faire quelques appels bien sentis avant de quitter le shell pour virer les variables indésirables :
          export CODE1= CODE2= CODE3=

          Je ne dispose pas de ksh pour tester, alors je vous laisse tester le tout pour voir ce que ça donne.
          • [^] # Re: ... malheureusement

            Posté par  . Évalué à 1.

            Bonjour,

            cette solution ne semble pas marcher:


            #!/bin/ksh
            { echo "valeur" ; export pid1=$$ ; echo $pid1 ; } &
            { echo "valeur" ; export pid2=$$ ; echo $pid2 ; } &
            { echo "valeur" ; export pid3=$$ ; echo $pid3 ; } &
            wait

            echo "Les pid sont $pid1 $pid2 $pid3"

            donne
            valeur
            10959
            valeur
            10959
            valeur
            10959
            Les pid sont


            L'export ne marche pas en l'occurence...
          • [^] # Re: ... malheureusement

            Posté par  . Évalué à 1.

            une derniere remarque sur un detail qui m'a posé pb un moment,

            dans le code que tu suggere

            { commande1 > fichier1 && export CODE1 = $? } &


            il faut mettre un ; a la fin, sinon, on obtient une erreur

            { commande1 > fichier1 && export CODE1 = $? ; } &


            sans doute un simple oubli de ta part, mais j'avoue que j'ai cherché un moment ;)

            Merci encore.
        • [^] # Re: ... malheureusement

          Posté par  . Évalué à 1.

          Bonjour,

          cette solution fonctionne bien. Effectivement, ce n'est pas très propre, mais ca fonctionne, ce qui est le plus important!

          Merci beaucoup!
  • # Parce que je suis tenace !

    Posté par  . Évalué à 2.

    Pourquoi ne pas procéder ainsi :
    code1 = `(commande1 > fichier1 ; echo $? ) &`
    code2 = `(commande2 > fichier2 ; echo $? ) &`
    code3 = `(commande3 > fichier3 ; echo $? )&`
    wait
    echo $code1, $code2, $code3

    J'ai pu tester avec un pauv' ksh que j'ai ressorti d'un vieux serveur...
    Ca semble fonctionner comme tu veux....
    • [^] # Re: Parce que je suis tenace ! et plein d'illusions...

      Posté par  . Évalué à 2.

      Salut,

      Désolé de te décevoir encore une fois, mais dans le code que tu donnes, les commandes ne sont pas exécutées en parallèle : l'affectation de la variable code1 doit être terminée pour que l'instruction suivante (code2 = `(commande2 > fichier2 ; echo $? ) &`) soit exécutée. Ça ne répond donc pas réellement au problème de départ de Paddle (exécution de plusieurs commandes en même temps avec récupération du code retour).

      Pour finir, si le coup de l'export des variables ne fonctionne pas, c'est parce que export permet de dupliquer des variables vers les sous-processus et non pas de les partager avec eux. En aucun cas la modification dans un sous-shell d'une variable exportée ne sera visible dans le shell appelant (et cela n'est pas spécifique à ksh).

      Je te félicite tout de même de ta persévérance.

      A+
      JJD
      • [^] # Re: Parce que je suis tenace ! et plein d'illusions...

        Posté par  . Évalué à 2.

        Quand tu en auras marre de démonter mes shells, tu me feras signe ;-) !
        Le pire, c'est que tu as une fois encore raison, mais là, je pense être plus proche de LA SOLUTION que jamais.....
        Que penses-tu de ça :

        code1 = `(commande1 > fichier1 ; echo $? ) ` &
        code2 = `(commande2 > fichier2 ; echo $? ) ` &
        code3 = `(commande3 > fichier3 ; echo $? )` &
        wait
        echo $code1, $code2, $code3

        En déplaçant les & en dehors des quotes, c'est l'affectation qui passe en arrière plan, et non seulement la tâche exécutée à droite du signe =.
        Là, je pense que ça peut fonctionner, ça, mince alors !

        Pour le coup de l'export, tu as fort raison, mais mes cours de shell sont bien loins maintenant, et je l'utilise si rarement que ... ben ... bref.
        En tout cas, le coup de la persévérance, c'est surtout pour ma culture personnelle et parce que je me dis que peut-être, un jour, ça me servira à quelque chose.
        D'ailleurs, j'utilise déjà quelque chose un peu dans ce genre, mais sans contrôle d'erreur... "Ce qui est bien mais pas top", comme dirait l'autre, et finalement, le problème de notre ami pourrait m'aider à résoudre le mien !
        Et puis merci à toi, car si tu trouves que je suis persévérant, tu sembles l'être au moins autant que moi puisque tu es toujours là pour me corriger !

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.