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:
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.
3 Réponses :
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
).
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.
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).
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>