Bagaimana cara menghentikan skrip bash loop di terminal?

55

Sebagai contoh,

#!/bin/bash
while :
do
    sl
done

Bagaimana cara menghentikan skrip bash ini?

Yinyanghu
sumber
1
Berikan detail lebih lanjut. Apakah Anda ingin menghentikannya secara interaktif atau terprogram?
manatwork
1
Anda dapat menekan ctrl-cuntuk mengirim SIGINTsinyal (di sebagian besar kulit) atau Anda dapat menekan ctrl-zyang mengirim SIGTSTPsinyal (di sebagian besar kulit). Jika Anda menekan ctrl-zproses yang terkait tidak terbunuh tetapi dihentikan sementara. Anda dapat melanjutkannya dengan fg(setidaknya dalam bash)
user1146332
Tidak, itu tidak berhasil!
Yinyanghu
4
Masalahnya bukan skrip, tapi slperintah yang saya percaya adalah perintah pengumuman untuk mereka yang salah mengeja ls, menunjukkan kereta api yang lewat perlahan. Sejauh yang saya tahu itu menangkap SIGINTsinyal dan harus dibunuh bersama SIGKILL.
1
Terima kasih. Tidak dikemas untuk distro saya, itu sebabnya saya tidak tahu / menemukannya. (Saya pikir saya tidak akan mengajukan permintaan untuk itu.)
manatwork

Jawaban:

64

Program slsengaja mengabaikannya SIGINT, yang dikirim saat Anda menekan Ctrl+C. Jadi, pertama-tama, Anda harus memberi tahu sluntuk tidak mengabaikan SIGINTdengan menambahkan -eargumen.

Jika Anda mencoba ini, Anda akan melihat bahwa Anda dapat menghentikan setiap individu sl, tetapi mereka masih mengulanginya. Anda perlu memberitahu bashuntuk keluar setelah SIGINTjuga. Anda dapat melakukan ini dengan meletakkan trap "exit" INTsebelum loop.

#!/bin/bash
trap "exit" INT
while :
do
    sl -e
done
Jim Paris
sumber
5
Saya tidak menginstalnya untuk memeriksa, tetapi Anda mungkin juga dapat membunuhnya dengan SIGQUIT dari Ctrl- \
derobert
121
  1. tekan Ctrl-Zuntuk menangguhkan skrip
  2. kill %%

The %%memberitahu bash built-in killyang Anda ingin mengirim sinyal (SIGTERM secara default) untuk pekerjaan latar belakang yang paling baru-baru ini ditangguhkan di shell saat ini, tidak dengan proses-id.

Anda juga dapat menentukan pekerjaan berdasarkan nomor atau nama. misal ketika Anda menangguhkan pekerjaan dengan ^ Z, bash akan memberi tahu Anda seperti apa nomor pekerjaannya dengan sesuatu [n]+ Stopped, di mana di ndalam kurung kotak adalah nomor pekerjaan.

Untuk info lebih lanjut tentang kontrol pekerjaan dan membunuh pekerjaan, menjalankan help jobs, help fg, help bg, dan help killdi bash, dan mencari JOB CONTROL(semua topi) atau jobspecdi halaman pesta pria.

misalnya

$ ./killme.sh 
./killme.sh: baris 4: sl: perintah tidak ditemukan
./killme.sh: baris 4: sl: perintah tidak ditemukan
./killme.sh: baris 4: sl: perintah tidak ditemukan
./killme.sh: baris 4: sl: perintah tidak ditemukan
./killme.sh: baris 4: sl: perintah tidak ditemukan
...
...
...
./killme.sh: baris 4: sl: perintah tidak ditemukan
^ Z
[1] + Berhenti ./killme.sh
$ kill %%
$ 
[1] + Dihentikan ./killme.sh

Dalam contoh ini, nomor pekerjaan adalah 1, jadi kill %1akan bekerja sama dengankill %%

(CATATAN: Saya tidak slmenginstal jadi outputnya hanya "perintah tidak ditemukan". Dalam kasus Anda, Anda akan mendapatkan output sl apa pun yang dihasilkan. Itu tidak penting - ^Ztunda dan kill %%akan bekerja sama)

cas
sumber
3
Jawaban bagus lainnya!
Yinyanghu
2
BTW, untuk mengeksekusi loop cepat seperti ini, ^ Z bisa menjadi cara yang lebih dapat diandalkan untuk membunuh proses daripada ^ C. ^ C akan dikirim ke program ( sl) dijalankan dalam loop, tetapi skrip akan tetap berjalan ... dan mulai yang lain sl. Jika Anda menekan ^ C beberapa kali dengan sangat cepat, Anda bisa mematikan slskrip dan skripnya (jika tidak ada yang menjebak SIGINT). ^ Z akan segera menangguhkan skripnya (segera jika Anda tidak menghitung output buffer yang masih dicetak ke terminal Anda), sehingga Anda dapat membunuhnya dengankill %%
cas
Persis! Saya harus mengatakan " sladalah program yang menyenangkan". Kali ini, itu menyenangkan saya lagi! @ _ @
Yinyanghu
Hanya jawaban yang tampaknya berfungsi juga ketika loop tidak dipanggil dari skrip tetapi dari baris perintah secara langsung.
Skippy le Grand Gourou
1
@DrewChapin Saya tidak ingat kapan / di mana saya mengetahuinya - hanya sesuatu yang saya kenal "sejak selamanya". Halaman bash man (mencari jobspec ) mengatakan: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

Jika Anda ingin ctrl + c menghentikan loop, tetapi tidak menghentikan skrip, Anda dapat menempatkan || breaksetelah perintah apa pun yang sedang Anda jalankan. Selama program yang Anda jalankan berakhir pada ctrl + c, ini berfungsi dengan baik.

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

Jika Anda berada di loop bersarang, Anda dapat menggunakan "break 2" untuk keluar dari dua level, dll.

Dale Anderson
sumber
1
plus 1 untuk break 2
flyingfinger
3

Anda dapat menghentikan skrip itu dengan menekan Ctrl + C dari terminal tempat Anda memulai skrip ini. Tentu saja skrip ini harus dijalankan di latar depan sehingga Anda dapat menghentikannya dengan Ctrl + C.

Atau Anda dapat menemukan PID (ID Proses) skrip itu di terminal lain yang dibuka dengan:

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

Kedua cara harus melakukan trik yang Anda minta.

panaroik
sumber
1
Itu tidak dapat diakhiri dengan Ctrl + C dari terminal. Jadi saya harus membunuhnya dengan ps atau atas. Saya hanya ingin tahu bagaimana cara membunuhnya secara langsung!
Yinyanghu
3

Cara termudah adalah dengan mengeluarkan QUITsinyal, yang biasanya melekat Control-Backslash.

Ketika Anda melihat kereta, tekan Control- \

RobertL
sumber
1

Anda dapat killmenggunakan pidshell (bash).
Saya baru saja mencoba dan berhasil.
Karena saya tidak dapat melihat proses dari ps -ef(pekerjaan yang kami jalankan di skrip pengulangan).

Suwarto
sumber
0

Cara lain untuk menghentikan seluruh skrip adalah dengan latar belakang slperintah dan kemudian menjebak sinyal INTuntuk membunuh seluruh kelompok proses skrip dengan sinyal HUP.

#!/bin/bash

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

while :
do
   sl & wait
done
chanze
sumber
-1

gunakan set -euntuk keluar dari kegagalan.

#!/bin/bash
set -e
while :
do
    sl
done
guo chun mao
sumber
Itu tidak akan berhasil. sltidak mati dengan 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

ini akan membantu.

coder007
sumber
2
Menurut Anda mengapa PID dari perintah latar belakang terakhir adalah 0?
manatwork
-1

Pembunuhan itu mengerikan, karena Anda tidak pernah sekarang, jika skrip harus dijalankan dua kali. DAN kode keluar Anda salah.

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

Tidak bekerja. Solusi = gunakan perl. saat membuka bash sendiri

rene
sumber