Journal waitend: exécuter une commande après une autre (déjà lancée)

Posté par (page perso) . Licence CC by-sa
Tags :
10
5
mar.
2013

Parfois, j'ai besoin de lancer une commande après qu'une autre (quelconque) est déjà été lancée. J'ai cherché et demandé sur le forum (merci pour les réponses!) s'il existait une commande pour faire cela.

Les réponses (bout de scripts shell, outils qui ne correspondent pas tout à fait au besoin) me confortent dans l'idée que ça n'existe pas (ou plus probablement que personne n'en connait un). J'en ai donc écrit un… C'est du python car c'est ce que je pratique au quotidien et que ce sera plus facile à étendre si j'en ressent le besoin par la suite.

L'outil s'appelle waitend car je sais que wait et waitproc sont déjà pris.
Il vérifie l'existence d'un PID ou le nom d'un processus régulièrement (par défaut toutes les minutes) et exécute la commande passée en second paramètre si le processus n'est pas trouvé.

Le code est disponible dans un dépôt github, sous licence GPLv3+.

  • # Merci l'artiste :-)

    Posté par (page perso) . Évalué à 2.

    C'est tout à fait le genre de truc que je me disais qu'il faudra que je fasse, mais que je n'ai jamais pris le temps de faire. Du coup, je ne le ferai jamais. Merci -:)

    Ton script est über pratique quand on a lancé un truc et qu'après-coup on veut surveiller la fin de l'exécution.

  • # Je comprend pas en quoi le shell te convient pas…

    Posté par . Évalué à 7.

    Exemple pour firefox :

        while pgrep firefox > /dev/null ; do sleep 60 ; done ; echo "Firefox est terminé (ou a planté misérablement)"
    
    

    Seulement le mien :

        while pgrep -U $UID firefox > /dev/null ; do sleep 60 ; done ; echo "Firefox est terminé (ou a planté misérablement)"
    
    
    • [^] # Re: Je comprend pas en quoi le shell te convient pas…

      Posté par (page perso) . Évalué à -3.

      Comme si Firefox plantait souvent ;)

      Sinon, autant ta solution semble fonctionnelle, autant je préfère son programme qui fournit une solution simple. Pourquoi faire systématiquement complexe alors quand on peut simplifier la vie des autres ?

      • [^] # Re: Je comprend pas en quoi le shell te convient pas…

        Posté par (page perso) . Évalué à 6.

        Parce que sur une machine lambda, tu as toujours le shell d'installé, mais jamais son programme.

        A mes yeux, la solution la plus simple est celle qu'on apprend une fois et qu'on réemploie ensuite partout …

      • [^] # Re: Je comprend pas en quoi le shell te convient pas…

        Posté par . Évalué à 5. Dernière modification le 06/03/13 à 11:16.

        mouais, j'allais faire un nouveau fil pour des critiques constructives de son programme ^

        • comment il se comporte si je lance un process s'appelant 0123456 => il considére que c'est un pid (bien trop grand) et donc exécute la commande après le délai spécifié ;)
        • aucun contrôle pour savoir comment s'est terminé la commande (&& || ;)

        Pourquoi faire systématiquement complexe alors quand on peut simplifier la vie des autres

        ça c'est pour l'attente avec pid, ça donne ça ^ j'aurais pas tendance à dire que c'est complexe, c'est même du bash très basique.

        while ps -p 1234 >/dev/null ; do sleep 60 ; done ; cmd

        tu peux même l'avoir avec waitpid(){ while ps -p $1 >/dev/null ; do sleep 60 ; done ; shift ; $* }

        pour l'attente d'un nom de process, il suffit de remplacer ps par pgrep [-u $USER] pattern.

        Enfin pour faire bref, en apprenant les briques de bases du shell, on apprend a pouvoir s'adapter.

        à noter que l'approche python et l'approche shell souffrent du même problème qui est la réapparition d'un process ayant le même nom/pid

        Il ne faut pas décorner les boeufs avant d'avoir semé le vent

    • [^] # Re: Je comprend pas en quoi le shell te convient pas…

      Posté par . Évalué à 4.

      Ou même && qui n'exécute la suite qu'en cas de succès de la précédente, où tu tape ça dans le shell à la suite et si il n'y a pas d'entrée, et que tu ne fait pas ctrl+C, ça s'exécute!

      • [^] # Re: Je comprend pas en quoi le shell te convient pas…

        Posté par (page perso) . Évalué à 4. Dernière modification le 05/03/13 à 22:30.

        Son problème est quand il n'a qu'une seule console, et il aimerait que le shell se libère pendant l'exécution de la commande.

        C'est pour parer à ça qu'il y a GNU Screen, et une surcouche Byobu plus simple à utiliser (quoi, Canonical fait des choses utiles ???) : tu lances un "shell" qui te permet de lancer d'autres shells si le shell actuel est déjà occupé. À noter que c'est pas très utile si tu peux utiliser des onglets dans ton terminal…

        Commentaire sous licence LPRAB - http://sam.zoy.org/lprab/

    • [^] # Re: Je comprend pas en quoi le shell te convient pas…

      Posté par (page perso) . Évalué à 6.

      Sauf que si tu veux matcher uniquement firefox, il faudra écrire : pgrep '^firefox$'.

      Et si le processus est lancé deux fois ? Et si le processus se coupe et se relance plus rapidement qu’un tour de boucle ?

    • [^] # Re: Je comprend pas en quoi le shell te convient pas…

      Posté par (page perso) . Évalué à 2.

      Oui, c'est tout à fait faisable dans un script shell. (Avant, je faisais des commandes de ce genre.) Par contre, pour un résultat équivalent à que ce que j'ai écrit le code va être plus compliqué que la ligne que tu as indiqué.

      À mon avis, avec le fonctionnement actuel, les solutions shell ou Python se valent. Si la complexité augmente, le rendement avec le shell sera plus faible qu'avec Python, d'où le choix de Python : rien à gagner à le faire avec du code shell et un gain potentiel futur à le faire en Python. (pari hypothétique et estimation très personnelle…)

  • # solution sans polling

    Posté par . Évalué à 10.

    Pour ceux qui trouvent que le polling c'est sale, il existe une interface du noyau linux à base de message, permettant de s'enquérir de ce qui se passe chez ces entités bizarres que l'on appelle processus.

    Un article qui explicite bien le tout : http://bewareofgeek.livejournal.com/2945.html

    • [^] # Re: solution sans polling

      Posté par (page perso) . Évalué à 0.

      gpicview &
      wait $(pgrep gpicview) && echo gpicfail
      
      

      (mais ça ne fonctionne qu'avec des tâches en background dans le même shell)

      • [^] # Re: solution sans polling

        Posté par . Évalué à 10.

        Oui, ou encore plus simple :

        commande &
        wait $!
        echo "commande terminée"
        
        

        Après, si on ne veux pas que ce soit dans le même shell, on peut mettre la commande suivante en écoute sur un fifo dans un autre shell, et y écrire une fois la première terminée (ou récupérer le PID avec ps, si on connaît la commande).

    • [^] # Re: solution sans polling

      Posté par . Évalué à 1.

      strace attaché à un processus s'arrête aussi avec la mort du processus

      • [^] # man bash

        Posté par . Évalué à 2.

        à tout hasard, man bash et une recherche sur "background" n'est pas pertinent ? Je n'ai pas du bien comprendre ce que tu recherches, mais pour moi & et la gestion des tâches dans bash répond à ta question.

    • [^] # Re: solution sans polling

      Posté par (page perso) . Évalué à 2.

      D'un autre côté le monsieur fait un fork+exec de ps depuis son brol en Python donc je crois que faire un truc propre et efficace est complètement hors sujet. Cela dit, avec ps il est potentiellement possible de faire quelque chose de plus portable qu'avec netlink (d'un autre côté, /proc (et donc ps) ne sont pas toujours dispos, même sous GNU/Linux).

      Quelques autres solutions qui pourraient être considérées :
      * inotify sur /proc/$pid
      * ptrace(2) (avec les risques de EPERM)
      * stap -e'probe kprocess.exit { system("whatever") }'

      Au final, "while [ -d /proc/$pid ] ; do sleep 1 ; done" me semble très bien et si on veut un vrai programme "stand alone" pour ça, il me semble que ça aurait plutôt sa place dans coreutils ou procps.

      pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.

  • # Solution depuis un terminal

    Posté par . Évalué à 10.

    Si la première commande est lancée depuis un terimal, tu peux l'interrompre avec ctrl+Z, et tu la relance avec fg && command 2

    je viens de tester sous bash, avec sleep 10 et echo "commande 2" ça marche au poil. (attention, sleep "continue de compter" quand tu fais ton ctrl+Z, donc si tu es lent à lancer la suite, tu peux avoir l'impression que ça a foiré car les 10 secondes sont passées depuis la lancement de sleep)

  • # Autre solution

    Posté par . Évalué à 10.

    Personnellement je fait
    Ctrl Z
    $ fg && cmd
    Mais je testerai waitend, qui à l'air un peu plus propre ;)

  • # Timeout et autres idées

    Posté par (page perso) . Évalué à 1.

    Salut,

    Sympa comme idée, j'ai aussi ressenti souvent le besoin. Dans la pratique je faisais un gros sleep en estimant le temps que mettrai le premier, mais ton truc est plus sympa.

    Je préconise une option timeout, pour lancer le programme suivant quand le timeout sera passé.

    Il peut être intéressant aussi de ne pas passer la commande en paramètre et de laisser la magie du shell opérer avec un && ou || suivant le comportement voulu (et alors retourner la valeur de retour du programme attendu, si c'est envisageable ?)

    • [^] # Re: Timeout et autres idées

      Posté par (page perso) . Évalué à 1.

      Il n'est pas possible de récupérer le résultat du processus attendu car il n'y a pas de lien entre waitend et le processus en question.

      Pour l'option --timeout, pourquoi pas mais je n'ai jamais vraiment ressenti ce besoin. Tu imagines des cas où c'est pertinent ?

Suivre le flux des commentaires

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