Come fermare lo script loop bash nel terminale?


55

Per esempio,

#!/bin/bash
while :
do
    sl
done

Come terminare questo script bash?


1
Dai maggiori dettagli. Vuoi fermarlo in modo interattivo o programmatico?
arte

1
puoi premere ctrl-cper inviare il SIGINTsegnale (nella maggior parte delle shell) oppure puoi premere per ctrl-zinviare il SIGTSTPsegnale (nella maggior parte delle shell). Nel caso in cui hai premuto ctrl-zil processo correlato non viene ucciso ma messo in pausa. Puoi riprenderlo con fg(almeno in bash)
user1146332

No, non funziona!
Yinyanghu,

4
Il problema non è la sceneggiatura, ma il slcomando che ritengo sia un comando fastidioso per chi scrive male ls, mostrando un treno che passa lentamente. Per quanto ne so, intrappola il SIGINTsegnale e deve essere ucciso SIGKILL.

1
Grazie. Non imballato per la mia distribuzione, ecco perché non lo sapevo / non l'ho trovato. (Penso che non presenterò una richiesta per questo.)
Manatwork

Risposte:


64

Il programma slignora di proposito SIGINT, che è ciò che viene inviato quando si preme Ctrl+C. Quindi, in primo luogo, dovrai dire di slnon ignorare SIGINTaggiungendo l' -eargomento.

Se provi questo, noterai che puoi fermare ogni individuo sl, ma continuano a ripetere. Devi dire bashdi uscire anche dopo SIGINT. Puoi farlo mettendo un trap "exit" INTprima del ciclo.

#!/bin/bash
trap "exit" INT
while :
do
    sl -e
done

5
Non ho installato per verificare, ma potresti anche essere in grado di ucciderlo con SIGQUIT da Ctrl- \
derobert

121
  1. premere Ctrl-Zper sospendere lo script
  2. kill %%

La %%racconta la bash built-in killche si desidera inviare un segnale (SIGTERM per impostazione predefinita) per il processo in background più recentemente sospeso nella shell corrente, non a un processo-id.

È inoltre possibile specificare i lavori per numero o per nome. ad es. quando sospendi un lavoro con ^ Z, bash ti dirà qual è il suo numero di lavoro con qualcosa del genere [n]+ Stopped, dove l' ninterno delle parentesi quadre è il numero del lavoro.

Per ulteriori informazioni sul controllo del lavoro e sui posti di lavoro uccidendo, correre help jobs, help fg, help bg, e help killin bash, e cercare JOB CONTROL(tutto maiuscolo) o jobspecnella pagina man di bash.

per esempio

$ ./killme.sh 
./killme.sh: riga 4: sl: comando non trovato
./killme.sh: riga 4: sl: comando non trovato
./killme.sh: riga 4: sl: comando non trovato
./killme.sh: riga 4: sl: comando non trovato
./killme.sh: riga 4: sl: comando non trovato
...
...
...
./killme.sh: riga 4: sl: comando non trovato
^ Z
[1] + Stopped ./killme.sh
$ kill %%
$ 
[1] + Terminato ./killme.sh

In questo esempio, il numero del lavoro era 1, quindi kill %1avrebbe funzionato comekill %%

(NOTA: non ho slinstallato, quindi l'output è solo "comando non trovato". Nel tuo caso, otterrai qualunque output prodotto da sl. Non è importante - la ^Zsospensione e kill %%funzionerà allo stesso modo)


3
Un'altra buona risposta!
Yinyanghu,

2
A proposito, per eseguire rapidamente cicli come questo, ^ Z può essere un modo più affidabile per terminare il processo di ^ C. ^ C verrà inviato al programma ( sl) in esecuzione nel ciclo, ma lo script continuerà a funzionare ... e ne avvierà un altro sl. Se premi ^ C alcune volte molto velocemente, potresti riuscire a uccidere sia sllo script che lo script (se nessuno dei due intercetta SIGINT). ^ Z sospenderà lo script quasi immediatamente (immediatamente se non conti l'output buffer che è ancora in fase di stampa sul tuo terminale), quindi puoi ucciderlo conkill %%
cas

Esattamente! Devo dire " slè un programma divertente". Questa volta, mi diverto di nuovo! @ _ @
Yinyanghu,

Solo risposta che sembra funzionare anche quando il loop non viene chiamato da uno script ma direttamente dalla riga di comando.
Skippy le Grand Gourou,

1
@DrewChapin Non ricordo quando / dove l'ho scoperto - solo qualcosa che ho conosciuto "da sempre". La pagina man di bash (cerca jobspec ) dice: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
cas

7

Se vuoi che ctrl + c fermi il ciclo, ma non termini lo script, puoi inserire || breakdopo qualunque comando tu stia eseguendo. Finché il programma che stai eseguendo termina con ctrl + c, questo funziona alla grande.

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

Se sei in loop nidificato, puoi usare "break 2" per uscire da due livelli, ecc.


1
più 1 per la pausa 2
flyingfinger

3

Puoi terminare quello script premendo Ctrl + C dal terminale da cui hai iniziato questo script. Naturalmente questo script deve essere eseguito in primo piano in modo da poterlo fermare con Ctrl + C.

Oppure puoi trovare il PID (Process ID) di quello script in un altro terminale aperto:

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

Entrambi i modi dovrebbero fare il trucco che stai chiedendo.


1
Non può essere terminato da Ctrl + C dal terminale. Quindi devo ucciderlo da ps o top. Voglio solo sapere come ucciderlo direttamente!
Yinyanghu,

3

Il modo più semplice è emettere il QUITsegnale, che di solito è collegato Control-Backslash.

Quando vedi il treno, premi Control- \


1

Puoi usare killla pidshell (bash).
Ho appena provato e funziona.
Perché non riesco a vedere il processo da ps -ef(il lavoro che eseguiamo nello script di loop).


0

Un altro modo per terminare l'intero script sarebbe quello di mettere in background il slcomando e quindi intercettare il segnale INTper uccidere l'intero gruppo di processi dello script con segnale HUP.

#!/bin/bash

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

while :
do
   sl & wait
done


-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

questo dovrebbe aiutare.


2
Perché pensi che il PID dell'ultimo comando in background sarà mai 0?
arte

-1

L'omicidio è terribile, perché non lo fai mai ora, se lo script deve essere eseguito due volte. E il tuo codice di uscita è sbagliato.

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

Non funziona. Soluzione = usa perl. mentre apre la propria bash

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.