4
votes

Attendez la fin du processus OU la saisie de l'utilisateur pour continuer

J'ai un script bash qui exécute une commande en arrière-plan. Après l'avoir exécuté, il affiche à l'utilisateur: Appuyez sur n'importe quelle touche pour continuer (alimenté par read -n1 -r -p 'Appuyez sur n'importe quelle touche pour continuer' valeur ) < / p>

Je voudrais que quelque chose surveille la commande en arrière-plan pour voir quand elle est terminée, et si c'est le cas, je veux que le script continue de toute façon. D'un autre côté, le processus pourrait toujours être en cours, et je voudrais permettre à l'utilisateur d'appuyer sur une touche pour tuer ce processus au lieu d'attendre qu'il se termine.


Je suppose que le moyen le plus simple de le visualiser serait comme ceci:

 mac shut down

L'utilisateur peut soit attendre que le minuteur passe à 0 et il s'éteigne automatiquement, soit s'il clique sur le bouton d'arrêt, il s'arrête immédiatement.


0 commentaires

3 Réponses :


2
votes

Quelque chose comme ça pourrait fonctionner pour vous

#!/bin/bash

doStuff() {
    local pidOfParent="$1"

    for i in $(seq 10); do
        echo "stuff ${i}" > /dev/null
        sleep 1
    done

    kill $pidOfParent
}

doStuff $$ &

doStuffPid="$!"

read -n1 -rp 'Press any key to continue' && kill $doStuffPid

Décomposer

doStuff est notre fonction qui contient ce que vous voulez exécuter en arrière-plan, c'est-à-dire la musique.

$$ est le PID du script en cours d'exécution, que nous transmettons à notre fonction pour devenir le pidOfParent dans lequel nous tuons après avoir fini de faire des choses.

Le & après avoir appelé la fonction le met en arrière-plan .

$! obtient le PID de la dernière commande exécutée, nous avons donc maintenant le PID du processus d'arrière-plan que nous venons de démarrer.

Vous avez fourni read -n1 -rp 'Appuyez sur n'importe quelle touche pour continuer' donc je peux supposer que vous savez déjà ce que cela fait, && kill $ doStuffPid va tuer le processus d'arrière-plan lorsque read est sorti (cela fonctionne également si vous terminez le script en utilisant ^C).


0 commentaires

3
votes

Si vous voulez attendre le pid jusqu'à ce que l'utilisateur frappe une clé, vous pouvez le faire comme suit:

./long_command.sh &
waitpid=$!
echo "Hit any key to continue or wait until the command finishes"
while kill -0 ${waitpid} > /dev/null ; do
    #if [[ ${#KEY} -gt 0 ]] ; then
    if read -n 1 -t 1 KEY ; then
        kill ${waitpid}
        break
    fi
done

Remplacez simplement long_command.sh par votre commander. Ici $! retourne le pid du dernier sous-processus démarré et kill -0 $ {waitpid} vérifie si le processus est toujours existant (il ne tue pas le processus). ps -q $ {waitpid} fonctionne également sous Linux, mais pas sur Mac - merci @leetbacoon de l'avoir mentionné. read -n 1 -t 1 signifie "lire un caractère, mais attendre seulement 1 seconde" (vous pouvez également utiliser des fractions comme 0,5 ici). Le statut de retour de cette commande dépend de, si elle a pu lire un caractère dans le temps spécifié, ou non.


3 commentaires

Cela a fonctionné pour moi, merci, mais j'ai dû utiliser kill -0 "$ {waitpid}" au lieu de ps -q $ {waitpid} car la version macOS de ps n'a pas cet indicateur.


Merci pour votre retour. kill -0 n'est même pas documenté dans la page de manuel Linux. Je suppose que cela signifie le signal 0, mais le signal zéro n'est pas répertorié si j'émets kill -l mais cela fonctionne également. bien tu l'as trouvé! Je le mets à jour dans la réponse car il semble plus portable.


Je ne me souviens pas où je l'ai vu mais kill -0 ne tue rien, il vérifie simplement si ce processus est en cours d'exécution. Si tel est le cas, le code de sortie est 0 . Si ce n'est pas le cas, le code de sortie est ≥ 1 (afaik c'est seulement 1 mais pour être sûr, je dirais ≥ 1).



1
votes

Si vous êtes prêt à utiliser les attentes intégrées, vous pouvez écrire:

expect <(cat <<'EOD'
spawn sleep 10
send_user "Press any key to continue\n"
stty raw -echo
expect {
  -i $user_spawn_id -re ".+" {}
  -i $spawn_id eof {}
}
EOD
)

où vous remplaceriez sleep 10 par votre processus.

p>


0 commentaires