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?


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

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.


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

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


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

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;

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`

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


0

Gunakan trap-

exit_()
{
    exit
}

while true
do
    echo 'running..'
    trap exit_ int
done
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.