Jak zatrzymać skrypt bash pętli w terminalu?

54

Na przykład,

#!/bin/bash
while :
do
    sl
done

Jak zakończyć ten skrypt bash?

Yinyanghu
źródło
1
Podaj więcej szczegółów. Czy chcesz to zatrzymać interaktywnie czy programowo?
manatwork
1
możesz nacisnąć, ctrl-caby wysłać SIGINTsygnał (w większości powłok) lub możesz nacisnąć, ctrl-zktóry wysyła SIGTSTPsygnał (w większości powłok). W przypadku naciśnięcia ctrl-zpowiązany proces nie zostanie zabity, ale wstrzymany. Możesz go wznowić za pomocą fg(przynajmniej w bash)
user1146332
Nie, to nie działa!
Yinyanghu,
4
Problemem nie jest skrypt, ale slpolecenie, które moim zdaniem jest poleceniem namaszczającym dla tych, którzy źle literują ls, pokazując powoli przejeżdżający pociąg. O ile mi wiadomo, wychwytuje SIGINTsygnał i musi zostać zabity SIGKILL.
1
Dzięki. Nie zapakowany dla mojej dystrybucji, dlatego go nie znałem / nie znalazłem. (Myślę, że nie
złożę

Odpowiedzi:

64

Program slcelowo ignoruje SIGINT, co jest wysyłane po naciśnięciu Ctrl+C. Po pierwsze, musisz powiedzieć, slaby nie ignorować SIGINT, dodając -eargument.

Jeśli spróbujesz tego, zauważysz, że możesz zatrzymać każdą osobę sl, ale wciąż się powtarzają. Musisz także powiedzieć, bashżeby wyjść SIGINT. Możesz to zrobić, umieszczając trap "exit" INTprzed pętlą.

#!/bin/bash
trap "exit" INT
while :
do
    sl -e
done
Jim Paris
źródło
5
Nie mam go zainstalowanego do sprawdzania, ale możesz również zabić go za pomocą SIGQUIT z Ctrl- \
derobert
120
  1. naciśnij, Ctrl-Zaby zawiesić skrypt
  2. kill %%

%%Opowiada bash wbudowany killże chcesz wysłać sygnał (SIGTERM domyślnie) do ostatnio zawieszone zadanie w tle w bieżącej powłoce, a nie do procesu-id.

Możesz także określić zadania według numeru lub nazwy. np. kiedy zawiesisz zadanie za pomocą ^ Z, bash powie ci, jaki jest jego numer zadania z czymś takim [n]+ Stopped, gdzie w nnawiasach kwadratowych jest numer zadania.

Aby uzyskać więcej informacji na temat pracy i kontroli pracy na zabijanie, uruchom help jobs, help fg, help bg, i help killw bash i szukać JOB CONTROL(wielkimi literami) lub jobspecna stronie atakujących człowieka.

na przykład

$ ./killme.sh 
./killme.sh: linia 4: sl: nie znaleziono polecenia
./killme.sh: linia 4: sl: nie znaleziono polecenia
./killme.sh: linia 4: sl: nie znaleziono polecenia
./killme.sh: linia 4: sl: nie znaleziono polecenia
./killme.sh: linia 4: sl: nie znaleziono polecenia
...
...
...
./killme.sh: linia 4: sl: nie znaleziono polecenia
^ Z
[1] + Zatrzymano ./killme.sh
$ kill %%
$ 
[1] + Zakończone ./killme.sh

W tym przykładzie numer zadania wynosił 1, więc kill %1działałby tak samo jakkill %%

(UWAGA: Nie slzainstalowałem, więc wyjście jest po prostu „komenda nie została znaleziona”. W twoim przypadku otrzymasz wszystko, co produkuje sl. To nie jest ważne - ^Zwstrzymanie i kill %%będzie działać tak samo)

cas
źródło
3
Kolejna dobra odpowiedź!
Yinyanghu,
2
BTW, do szybkiego wykonywania takich pętli ^ Z może być bardziej niezawodnym sposobem na zabicie procesu niż ^ C. ^ C zostanie wysłane do programu ( sl) uruchamianego w pętli, ale skrypt będzie działał ... i uruchomi inny sl. Jeśli naciśniesz ^ C kilka razy naprawdę szybko, możesz zabić zarówno slskrypt, jak i skrypt (jeśli żadne z nich nie pułapki SIGINT). ^ Z niemal natychmiast zawiesi skrypt (natychmiast, jeśli nie policzysz buforowanego wyjścia, które wciąż jest drukowane na twoim terminalu), więc możesz go zabić za pomocąkill %%
cas
Dokładnie! Muszę powiedzieć „ slto fajny program”. Tym razem znów mnie to cieszy! @ _ @
Yinyanghu,
Tylko odpowiedź, która wydaje się działać również wtedy, gdy pętla nie jest wywoływana ze skryptu, ale bezpośrednio z wiersza poleceń.
Skippy le Grand Gourou
1
@DrewChapin Nie pamiętam, kiedy / gdzie się o tym dowiedziałem - po prostu coś, co znałem „od zawsze”. Strona podręcznika użytkownika bash (wyszukiwanie specyfikacji zadań ) mówi: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
6

Jeśli chcesz, aby ctrl + c zatrzymał pętlę, ale nie zakończył skryptu, możesz umieścić || breakpo dowolnej komendzie, którą uruchomisz. Tak długo, jak uruchamiany program kończy się na ctrl + c, działa to świetnie.

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

Jeśli jesteś w zagnieżdżonej pętli, możesz użyć „break 2”, aby wyjść z dwóch poziomów itp.

Dale Anderson
źródło
plus 1 za przerwę 2
flyingfinger
3

Możesz zakończyć ten skrypt, naciskając Ctrl + C z terminala, w którym uruchomiono ten skrypt. Oczywiście ten skrypt musi działać na pierwszym planie, aby można go było zatrzymać za pomocą Ctrl + C.

Możesz też znaleźć PID (identyfikator procesu) tego skryptu w innym otwartym terminalu, wykonując:

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

Oba sposoby powinny zrobić lewę, o którą prosisz.

panaroik
źródło
1
Nie można go zakończyć Ctrl + C z terminala. Więc muszę go zabić ps lub top. Chcę tylko wiedzieć, jak to zabić bezpośrednio!
Yinyanghu,
3

Najłatwiej jest wydać QUITsygnał, do którego zwykle jest dołączony Control-Backslash.

Gdy zobaczysz pociąg, naciśnij Control- \

RobertL
źródło
1

Można powłoki (bash). Właśnie próbowałem i działa. Ponieważ nie widzę procesu z (zadanie, które uruchamiamy w skrypcie zapętlającym).killpid

ps -ef

Suwarto
źródło
0

Innym sposobem zakończenia całego skryptu byłoby umieszczenie slpolecenia w tle, a następnie przechwycenie sygnału, INTaby zabić całą grupę procesów skryptu za pomocą sygnału HUP.

#!/bin/bash

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

while :
do
   sl & wait
done
chanze
źródło
-1

użyj, set -eaby wyjść z awarii.

#!/bin/bash
set -e
while :
do
    sl
done
guo chun mao
źródło
To nie zadziała. slnie umiera z 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

to powinno pomóc.

coder007
źródło
2
Jak myślisz, dlaczego PID ostatniego polecenia w tle wyniesie 0?
manatwork
-1

Zabijanie jest okropne, ponieważ nigdy teraz, jeśli skrypt musi zostać uruchomiony dwukrotnie. I twój kod wyjścia jest nieprawidłowy.

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

Nie pracuje. Rozwiązanie = użyj perla. podczas gdy otwiera własne bash

przedłużyć
źródło