47 votes

Comment exécuter une commande après la fin d'une autre déjà en cours d'exécution ?

Si je commence un script qui va prendre beaucoup de temps, je m'en rends inévitablement compte après avoir commencé le script, et j'aimerais avoir un moyen de faire une sorte d'alerte une fois qu'il est terminé.

Ainsi, par exemple, si je cours :

really_long_script.sh

Comment puis-je lancer une autre commande une fois qu'elle est terminée ?

59voto

aland Points 2810

Vous pouvez séparer plusieurs commandes par ; Ils sont donc exécutés de manière séquentielle, par exemple :

really_long_script.sh ; echo Finished

Si vous souhaitez exécuter le programme suivant uniquement si le script s'est terminé avec le code de retour 0 (ce qui signifie généralement qu'il s'est exécuté correctement), alors.. :

really_long_script.sh && echo OK

Si vous souhaitez l'inverse (c'est-à-dire continuer seulement si la commande en cours a échoué), alors :

really_long_script.sh || echo FAILED

Vous pouvez exécuter votre script en arrière-plan (mais attention, la sortie des script ( stdout y stderr ) continuerait à aller vers votre terminal à moins que vous ne le redirigiez quelque part), et ensuite wait pour cela :

really_long_script.sh &
dosomethingelse
wait; echo Finished

Si vous avez déjà exécuté script, vous pouvez le suspendre avec Ctrl-Z puis exécutez quelque chose comme :

fg ; echo Finished

fg ramène le processus suspendu au premier plan ( bg le ferait tourner en arrière-plan, un peu comme si l'on avait commencé avec & )

25voto

sai_ekkaldevi Points 41

Si le processus ne s'exécute pas sur le tty actuel, essayez ceci :

watch -g ps -opid -p <pid>; mycommand

17voto

Jaap Eldering Points 8835

Vous pouvez également utiliser le contrôle des tâches de bash. Si vous avez lancé

$ really_long_script.sh

puis appuyez sur ctrl+z pour le suspendre :

^Z
[1]+  Stopped                 really_long_script.sh
$ bg

pour redémarrer le travail en arrière-plan (comme si vous l'aviez démarré avec really_long_script.sh & ). Vous pouvez ensuite attendre ce travail d'arrière-plan avec

$ wait N && echo "Successfully completed"

où N est l'ID du travail (probablement 1 si vous n'avez pas exécuté d'autres travaux en arrière-plan), qui est également affiché sous la forme suivante [1] ci-dessus.

3voto

Coxy Points 5256

Il s'avère que ce n'est pas si difficile : il suffit de taper la commande suivante dans la fenêtre pendant que la commande existante s'exécute, d'appuyer sur la touche Entrée et, lorsque la première commande se termine, la seconde s'exécute automatiquement.

Je suppose qu'il existe des méthodes plus élégantes, mais celle-ci semble fonctionner.

Si vous souhaitez lancer une alerte après la fin de la commande, vous pouvez créer ces alias dans .bashrc, puis lancer alert pendant qu'il fonctionne :

 alias alert_helper='history|tail -n1|sed -e "s/^\s*[0-9]\+\s*//" -e "s/;\s*alert$//"'
 alias alert='notify-send -i gnome-terminal "Finished Terminal Job" "[$?] $(alert_helper)"'

1voto

Drumbeg Points 101

Il y a quelques temps, j'ai écrit un script pour attendre la fin d'un autre processus. NOISE_CMD pourrait être quelque chose comme notify-send ... étant donné que DISPLAY est correctement réglé.

#!/bin/bash

NOISE_CMD="/usr/bin/mplayer -really-quiet $HOME/sfx/alarm-clock.mp3"

function usage() {
    echo "Usage: $(basename "$0") [ PROCESS_NAME [ PGREP_ARGS... ] ]"
    echo "Helpful arguments to pgrep are: -f -n -o -x"
}

if [ "$#" -gt 0 ] ; then
    PATTERN="$1"
    shift
    PIDS="$(pgrep "$PATTERN" "$@")"

    if [ -z "$PIDS" ] ; then
        echo "No process matching pattern \"$PATTERN\" found."
        exit
    fi

    echo "Waiting for:"
    pgrep -l "$PATTERN" "$@"

    for PID in $PIDS ; do
        while [ -d "/proc/$PID" ] ; do
            sleep 1
        done
    done
fi

exec $NOISE_CMD

Sans aucun argument, il suffit de faire du bruit immédiatement. Ce comportement permet de faire quelque chose comme ceci par commodité (disons que vous appelez script ci-dessous alarm.sh ) :

apt-get upgrade ; ~/bin/alarm.sh

Bien sûr, vous pouvez faire beaucoup de choses amusantes avec un tel script, comme laisser une instance de alarm.sh attendre une instance de alarm.sh qui attend une autre commande. Ou exécuter une commande juste après la fin d'une tâche d'un autre utilisateur connecté... >:D

Une ancienne version du script ci-dessus pourrait être intéressante, si vous voulez éviter de dépendre de pgrep et accepter de rechercher vous-même les identifiants de processus :

#!/bin/bash

if [ "$#" -lt 2 -o ! -d "/proc/$1" ] ; then
  echo "Usage: $(basename "$0") PID COMMAND [ ARGUMENTS... ]"
  exit
fi

while [ -d "/proc/$1" ] ; do
  sleep 1
done

shift
exec "$@"

Légèrement hors sujet, mais utile dans des situations similaires : On peut s'intéresser à reptyr Un outil qui "vole" un processus d'un Shell (parent) et l'exécute dans le Shell actuel. J'ai essayé des implémentations similaires et reptyr est le plus beau et le plus fiable pour mes besoins.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X