Comment arrêter le script bash en boucle en terminal?

55

Par exemple,

#!/bin/bash
while :
do
    sl
done

Comment terminer ce script bash?

Yinyanghu
la source
1
Donnez plus de détails. Voulez-vous l'arrêter de manière interactive ou par programme?
manatwork
1
vous pouvez appuyer sur ctrl-cpour envoyer le SIGINTsignal (dans la plupart des coques) ou sur ctrl-zqui envoie le SIGTSTPsignal (dans la plupart des coques). Dans le cas où vous avez appuyé sur ctrl-zle processus associé, ce n'est pas tué, mais en pause. Vous pouvez le reprendre avec fg(au moins dans bash)
user1146332
Non, ça ne marche pas!
Yinyanghu
4
Le problème n’est pas le script, mais la slcommande que j’estime être une commande annotante pour ceux qui mal orthographient ls, montrant un train qui passe lentement. Autant que je sache, il intercepte le SIGINTsignal et doit être tué SIGKILL.
1
Merci. Pas emballé pour ma distribution, c'est pourquoi je ne l'ai pas su / trouvé. (Je pense que je ne vais pas déposer une demande pour cela.)
manatwork

Réponses:

64

Le programme slignore délibérément SIGINT, ce qui est envoyé lorsque vous appuyez sur Ctrl+C. Donc, tout d’abord, vous devrez dire de slne pas ignorer SIGINTen ajoutant l’ -eargument.

Si vous essayez ceci, vous remarquerez que vous pouvez arrêter chaque individu sl, mais ils répètent encore. Vous devez aussi dire bashde quitter après SIGINT. Vous pouvez le faire en mettant un trap "exit" INTavant la boucle.

#!/bin/bash
trap "exit" INT
while :
do
    sl -e
done
Jim Paris
la source
5
Je ne l'ai pas installé pour le vérifier, mais vous pourrez peut-être aussi le tuer avec SIGQUIT de Ctrl- \
derobert le
121
  1. appuyez sur Ctrl-Zpour suspendre le script
  2. kill %%

Le %%dit le bash intégré killque vous voulez envoyer un signal (SIGTERM par défaut) pour le travail de fond le plus récemment suspendu dans la coquille en cours, et non à un processus id.

Vous pouvez également spécifier des travaux par numéro ou par nom. Par exemple, lorsque vous suspendez un travail avec ^ Z, bash vous indiquera quel est son numéro de travail avec quelque chose comme [n]+ Stopped, où l' nintérieur entre crochets est le numéro du travail.

Pour plus d' informations sur le contrôle de l' emploi et sur les emplois à tuer, courir help jobs, help fg, help bget help killen bash, et rechercher JOB CONTROL(majuscules) ou jobspecdans la page de manuel bash.

par exemple

$ ./killme.sh 
./killme.sh: ligne 4: sl: commande non trouvée
./killme.sh: ligne 4: sl: commande non trouvée
./killme.sh: ligne 4: sl: commande non trouvée
./killme.sh: ligne 4: sl: commande non trouvée
./killme.sh: ligne 4: sl: commande non trouvée
...
...
...
./killme.sh: ligne 4: sl: commande non trouvée
^ Z
[1] + Stopped ./killme.sh
$ kill %%
$ 
[1] + Terminé ./killme.sh

Dans cet exemple, le numéro de travail était 1, il kill %1aurait donc fonctionné de la même manière quekill %%

(NOTE: Je n'ai pas sl. Installé de sorte que la sortie est juste « command not found » dans votre cas, vous obtiendrez ce que la sortie sl produit , il n'a pas d' importance - la. ^ZSuspendent et kill %%travaillerez même)

cas
la source
3
Une autre bonne réponse!
Yinyanghu
2
BTW, pour exécuter rapidement des boucles comme celle-ci, ^ Z peut être un moyen plus fiable de tuer le processus que ^ C. ^ C sera envoyé au programme ( sl) en cours d'exécution dans la boucle, mais le script continuera à s'exécuter ... et en démarrera un autre sl. Si vous appuyez rapidement plusieurs fois sur ^ C, vous pouvez tuer slle script et le script (si aucun d’eux ne piège SIGINT). ^ Z suspendra le script presque immédiatement (immédiatement si vous ne comptez pas la sortie en mémoire tampon qui est encore en cours d'impression sur votre terminal), afin que vous puissiez le tuer aveckill %%
cas
Exactement! Je dois dire " slest un programme amusant". Cette fois, ça m'amuse encore! @ _ @
Yinyanghu le
Seule réponse qui semble fonctionner également lorsque la boucle n'est pas appelée à partir d'un script, mais directement en ligne de commande.
Skippy le Grand Gourou
1
@DrewChapin Je ne me souviens plus du moment ni de l'endroit où je l'ai découvert - c'est quelque chose que je connais "depuis toujours". La page de manuel bash (recherche jobspec ) dit:The symbols %% and %+ refer to the shell's notion of the current job, which is the last job stopped while it was in the foreground or started in the background. The previous job may be referenced using %-. If there is only a single job, %+ and %- can both be used to refer to that job
ČAS
7

Si vous voulez que ctrl + c arrête la boucle mais ne termine pas le script, vous pouvez placer || breakaprès la commande que vous exécutez. Tant que le programme que vous exécutez se termine sur ctrl + c, cela fonctionne très bien.

#!/bin/bash
while :
do
    # ctrl+c terminates sl, but not the shell script
    sl -e || break
done

Si vous êtes dans une boucle imbriquée, vous pouvez utiliser "break 2" pour sortir de deux niveaux, etc.

Dale Anderson
la source
1
plus 1 pour la pause 2
flyingfinger
3

Vous pouvez terminer ce script en appuyant sur Ctrl + C depuis le terminal où vous avez commencé ce script. Bien sûr, ce script doit être exécuté en avant-plan pour pouvoir être arrêté par Ctrl + C.

Ou vous pouvez trouver le PID (ID de processus) de ce script dans un autre terminal ouvert en:

ps -ef | grep <name_of_the_script>
kill -9 <pid_of_your_running_script>

Les deux manières devraient faire le tour que vous demandez.

Panaroik
la source
1
Il ne peut pas être terminé par Ctrl + C à partir du terminal. Je dois donc le tuer par ps ou en haut. Je veux juste savoir comment le tuer directement!
Yinyanghu
3

Le moyen le plus simple est d’émettre le QUITsignal, qui est généralement associé à Control-Backslash.

Quand vous voyez le train, appuyez sur Control- \

RobertL
la source
1

Vous pouvez killle pidde shell (bash).
Je viens d'essayer et ça marche.
Parce que je ne peux pas voir le processus ps -ef(le travail que nous exécutons dans le script en boucle).

Suwarto
la source
0

Une autre façon de terminer le script entier consiste à mettre en arrière-plan la slcommande, puis à intercepter le signal INTafin de tuer le groupe de processus entier du script avec signal HUP.

#!/bin/bash

trap 'trap - INT; kill -s HUP -- -$$' INT
#trap 'trap - INT; kill -s HUP 0' INT

while :
do
   sl & wait
done
chanze
la source
-1

utiliser set -epour sortir de l'échec.

#!/bin/bash
set -e
while :
do
    sl
done
guo chun mao
la source
Ça ne marchera pas. slne meurt pas avec ctrl + c.
Duncan X Simpson
-1
while [ true ] 
do

  #check if script is running
  ps | grep script_name.sh | grep -v grep >/dev/null 2>&1

  if [ "$!" != "0" ] ; then
    break
  else

    kill -9 ` ps -ef | grep script_name.sh | cut -d "a" -f 1` 
    echo "kill -9 `get script PID`"

  fi

done

cela devrait aider.

coder007
la source
2
Pourquoi pensez-vous que le PID de la dernière commande d'arrière-plan sera 0?
manatwork
-1

Le meurtre est affreux, parce que vous ne devez plus jamais si le script doit être exécuté deux fois. ET votre code de sortie est faux.

while [ something ]; do

 if [ somethingelse ]; then
   echo shut down script with exit code 0
   exit 0
 fi
done

echo something else not happend
exit 2 # Return val important for example for monitoring

Ne pas travailler. Solution = utilisez perl. en ouvrant sa propre bash

rene
la source