web-dev-qa-db-fra.com

Comment exécuter une commande après une exécution déjà existante?

Si je commence un script qui va prendre beaucoup de temps, je le réalise inévitablement une fois que j'ai commencé le script et je souhaite avoir une façon de faire une sorte d'alerte une fois qu'il est terminé.

Donc, par exemple, si je lance:

really_long_script.sh

et appuyez sur Entrée ... comment puis-je exécuter une autre commande une fois qu'elle est terminée?

30
mlissner

Vous pouvez séparer plusieurs commandes par ; afin qu'elles soient exécutées 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 a terminé avec le code retour 0 (ce qui signifie généralement qu'il s'est correctement exécuté), alors:

really_long_script.sh && echo OK

Si vous voulez l’inverse (c’est-à-dire continuer uniquement 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, les scripts générés (stdout et stderr) continueront d’être envoyés à votre terminal, sauf si vous le redirigez quelque part), puis wait pour cela:

really_long_script.sh &
dosomethingelse
wait; echo Finished

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

fg ; echo Finished

fg affiche le processus suspendu au premier plan (bg le ferait exécuter en arrière-plan, un peu comme si on avait commencé avec &)

43
aland

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

$ really_long_script.sh

puis appuyez sur ctrl + z pour le suspendre:

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

pour relancer le travail en arrière-plan (comme si vous l'aviez lancé avec really_long_script.sh &). Ensuite, vous pouvez attendre ce travail en arrière-plan avec

$ wait N && echo "Successfully completed"

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

12
Jaap Eldering

Si le processus ne s'exécute pas sur le terminal en cours, essayez ceci:

watch -g ps -opid -p <pid>; mycommand
9
Marinos An

Il s'avère que ce n'est pas si difficile: vous pouvez simplement taper la commande suivante dans la fenêtre pendant que la commande existante est exécutée, appuyez sur entrée, et lorsque la première est terminée, la deuxième commande est exécutée automatiquement.

Je devine qu'il y a des manières plus élégantes, mais cela semble fonctionner.

Modification pour ajouter que si vous souhaitez exécuter une alerte une fois la commande terminée, vous pouvez créer ces alias dans .bashrc, puis exécuter alert pendant son exécution:

 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)"'
2
mlissner

Il y a quelque 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 défini correctement.

#!/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 arrêt, faites du bruit immédiatement. Ce comportement permet quelque chose comme ceci pour plus de commodité (disons que vous appelez le 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 bien exécuter une commande juste après qu'une tâche d'un autre utilisateur connecté est terminée ...>: D

Une ancienne version du script ci-dessus peut être intéressante si vous souhaitez éviter une dépendance à pgrep et accepter de rechercher vous-même les ID 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 pourrait être intéressé par reptyr , un outil qui "vole" un processus de certains Shell (parent) et l'exécute à partir de Shell actuel. J'ai essayé des implémentations similaires et reptyr est la plus jolie et la plus fiable pour mes besoins.

1
Piscoris