Mengakhiri loop tak terbatas

52

Saya memiliki perintah yang ingin saya jalankan lagi secara otomatis setiap kali berakhir, jadi saya menjalankan sesuatu seperti ini:

while [ 1 ]; do COMMAND; done;

tetapi jika saya tidak bisa menghentikan loop dengan Ctrl-ckarena hanya membunuh COMMANDdan bukan seluruh loop.

Bagaimana saya bisa mencapai sesuatu yang serupa tetapi saya bisa berhenti tanpa harus menutup terminal?

howardh
sumber
11
Jika saya dalam bash, saya hanya menggunakan Ctrl-Z untuk menghentikan pekerjaan dan kemudian "bunuh% 1" untuk membunuhnya.
Paul Cager
3
Tunggu saja ... Linus seperti dikutip: “Kita semua tahu Linux besar ... itu tidak loop tak terbatas dalam 5 detik” - sehingga benar-benar ... tunggu beberapa detik lagi, harus menyelesaikan.
lornix
@ PaulCager bekerja untuk saya juga! Mengapa ini bekerja di mana Ctrl-C tidak?
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
@cirosantilli itu membunuh pekerjaan luar (bash "wrapper"). Dalam beberapa situasi, itu tidak akan langsung membunuh "PERINTAH", misalnya, jika Anda latar belakang itu, itu mungkin menyelinap hidup-hidup bahkan jika orang tuanya mati. Tetapi loop sudah mati, dan itulah bagian yang penting.
orion

Jawaban:

38

Periksa status keluar dari perintah. Jika perintah diakhiri oleh sinyal, kode keluar akan menjadi 128 + nomor sinyal. Dari dokumentasi online GNU untuk bash :

Untuk tujuan shell, perintah yang keluar dengan status keluar nol telah berhasil. Status keluar yang tidak nol menunjukkan kegagalan. Skema yang tampaknya kontra-intuitif ini digunakan sehingga ada satu cara yang jelas untuk menunjukkan keberhasilan dan berbagai cara untuk menunjukkan berbagai mode kegagalan. Ketika sebuah perintah berakhir pada sinyal fatal yang jumlahnya N, Bash menggunakan nilai 128 + N sebagai status keluar.

POSIX juga menentukan bahwa nilai perintah yang diakhiri oleh sinyal lebih besar dari 128, tetapi tampaknya tidak menentukan nilai persisnya seperti yang dilakukan GNU:

Status keluar dari perintah yang diakhiri karena menerima sinyal harus dilaporkan lebih besar dari 128.

Sebagai contoh jika Anda mengganggu perintah dengan kontrol-C kode keluar akan menjadi 130, karena SIGINT adalah sinyal 2 pada sistem Unix. Begitu:

while [ 1 ]; do COMMAND; test $? -gt 128 && break; done
Kyle Jones
sumber
9
Harus disebutkan bahwa ini tidak dijamin, pada kenyataannya, banyak aplikasi tidak akan melakukan ini.
Chris Down
1
@Kyle Jones: dapatkah Anda menautkan ke dokumen POSIX / GNU yang menyebutkan itu?
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
@cirosantilli Selesai.
Kyle Jones
@KyleJones terima kasih! Masih dalam prakteknya tidak bekerja untuk COMMAND = paplay alert.ogg, mungkin karena paplaymenangani sinyal?
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
@cirosantilli Ya, itulah alasannya. Jika suatu proses menangani sinyal dan berhenti, itu berbeda dari proses yang diakhiri oleh sinyal tidak tertangani.
Kyle Jones
49

Anda bisa berhenti dan meletakkan pekerjaan Anda di latar belakang saat sedang berjalan menggunakan ctrl+ z. Maka Anda dapat membunuh pekerjaan Anda dengan:

$ kill %1

Di mana [1] adalah nomor pekerjaan Anda.

Jem
sumber
Lihat juga jawaban ini untuk penjelasan dan lainnya.
Skippy le Grand Gourou
2
Jawaban yang relatif baru ini hanya berfungsi. Perlu ditingkatkan. +1
shivams
Anda banyak membantu saya. Inilah yang saya cari dalam pertanyaan ini :)
Maximilian Ruta
18

Saya akan mengatakan itu mungkin yang terbaik untuk menempatkan loop tak terbatas Anda dalam skrip dan menangani sinyal di sana. Inilah titik awal dasar . Saya yakin Anda ingin memodifikasinya sesuai. Script digunakan trapuntuk menangkap ctrl- c(atau SIGTERM), mematikan perintah (Saya telah menggunakan di sleepsini sebagai tes) dan keluar.

cleanup ()
{
kill -s SIGTERM $!
exit 0
}

trap cleanup SIGINT SIGTERM

while [ 1 ]
do
    sleep 60 &
    wait $!
done
ephsmith
sumber
4
Bagus. Inilah cara saya menggunakan tip ini untuk membuat pembungkus netcat autorestarting:trap "exit 0" SIGINT SIGTERM; while true; do netcat -l -p 3000; done
Douglas
2
jika Anda menambahkan trappendekatan ini ke skrip (bash) yang sama dengan loop tak terhingga untuk dibunuh, gunakan $$alih-alih $!(lihat di sini )
ardnew
15

Saya biasanya hanya tahan Ctrl-C. Cepat atau lambat itu akan mendaftar antara COMMANDdan dengan demikian mengakhiri whileloop. Mungkin ada cara yang lebih baik.

jw013
sumber
1
Tidak yakin mengapa, tetapi gagal untuk PERINTAH tertentu seperti paplaypada file 1s.
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
Itu bekerja untuk saya
alexandr
Itulah kekuatan kasar dari semua solusi di sini. : /
markroxor
8

Jika Anda menjalankan bash -edengannya akan keluar pada kondisi kesalahan apa pun:

#!/bin/bash -e
false # returns 1
echo This won't be printed
Pasang kembali Monica
sumber
8

Kenapa tidak sederhana saja,

while [ 1 ]; do COMMAND || break; done;

Atau saat digunakan dalam naskah,

#!/bin/bash
while [ 1 ]; do
  # ctrl+c terminates COMMAND and exits the while loop
  # (assuming COMMAND responds to ctrl+c)
  COMMAND || break
done;
Dale Anderson
sumber
1
Solusi yang sangat elegan. Tetapi tidakkah ini hanya bekerja jika PERINTAH selalu mengembalikan status keluar yang sukses?
howardh
Ya @ howardh, itu benar.
Dale Anderson
3

Saya lebih suka solusi lain:

touch .runcmd; while [ -f ".runcmd" ]; do COMMAND; sleep 1; done

Untuk mematikan loop, lakukan saja:

rm .runcmd && kill `pidof COMMAND`
M4tze
sumber
2
  1. Anda selalu dapat mematikan proses menggunakan PID-nya, tidak perlu menutup terminal Anda
  2. Jika Anda ingin menjalankan sesuatu dalam loop tak terbatas seperti daemon maka sebaiknya Anda meletakkannya di latar belakang
  3. while : akan membuat loop tak terbatas dan menghemat Anda menulis [ 1 ]

    while :; do COMMAND; done &

Ini akan mencetak PID. Jika Anda keluar dari prompt Anda menggunakan ctrl+dmaka pekerjaan latar belakang tidak akan berhenti, dan Anda kemudian dapat membunuh pekerjaan dari mana saja menggunakankill PID

Jika Anda kehilangan jejak PID Anda, Anda dapat menggunakan pstree -pa $USERatau pgrep -fl '.*PROCESS.*'untuk membantu Anda menemukannya

errant.info
sumber
0

Gunakan trap-

exit_()
{
    exit
}

while true
do
    echo 'running..'
    trap exit_ int
done
markroxor
sumber