Saya memiliki skrip bash yang meluncurkan proses anak yang macet (sebenarnya, hang) dari waktu ke waktu dan tanpa alasan yang jelas (sumber tertutup, jadi tidak banyak yang bisa saya lakukan mengenai hal itu). Sebagai hasilnya, saya ingin dapat meluncurkan proses ini untuk jumlah waktu tertentu, dan membunuhnya jika tidak berhasil kembali setelah jumlah waktu tertentu.
Apakah ada cara sederhana dan kuat untuk mencapainya menggunakan bash?
PS: beri tahu saya apakah pertanyaan ini lebih cocok untuk serverfault atau superuser.
Jawaban:
(Seperti yang terlihat di: BASH FAQ entri # 68: "Bagaimana saya menjalankan perintah, dan membatalkannya (batas waktu) setelah N detik?" )
Jika Anda tidak keberatan mengunduh sesuatu, gunakan
timeout
(sudo apt-get install timeout
) dan gunakan seperti: (sebagian besar Sistem sudah menginstalnya jika tidak gunakansudo apt-get install coreutils
)Jika Anda tidak ingin mengunduh sesuatu, lakukan apa yang dilakukan timeout secara internal:
Jika Anda ingin melakukan timeout untuk kode bash yang lebih lama, gunakan opsi kedua seperti itu:
sumber
cmdpid=$BASHPID
tidak akan mengambil pid dari shell panggilan tetapi subshell (pertama) yang dimulai oleh()
. The(sleep
... Hal panggilan subkulit kedua dalam subkulit pertama yang menunggu 10 detik di latar belakang dan membunuh subkulit pertama yang, setelah meluncurkan proses subkulit pembunuh, hasil untuk melaksanakan beban kerja ...timeout
adalah bagian dari GNU coreutils, jadi harus sudah diinstal di semua sistem GNU.timeout
sekarang menjadi bagian dari coreutils.atau untuk mendapatkan kode keluar juga:
sumber
kill -9
sebelum Anda mencoba sinyal bahwa suatu proses dapat diproses terlebih dahulu.dosmth
berakhir dalam 2 detik, proses lain mengambil pid lama, dan Anda membunuh yang baru?sumber
sleep 999
sini) sering selesai lebih cepat dari pada tidur yang dikenakan (sleep 10
)? Bagaimana jika saya ingin memberikannya kesempatan hingga 1 menit, 5 menit? Bagaimana jika saya memiliki banyak kasus seperti itu dalam skrip saya :)Saya juga punya pertanyaan ini dan menemukan dua hal lagi yang sangat berguna:
Jadi saya menggunakan sesuatu seperti ini di baris perintah (OSX 10.9):
Karena ini adalah loop, saya menyertakan "sleep 0.2" untuk menjaga CPU tetap dingin. ;-)
(BTW: ping adalah contoh yang buruk, Anda hanya akan menggunakan opsi "-t" (batas waktu) bawaan.)
sumber
Dengan asumsi Anda memiliki (atau dapat dengan mudah membuat) file pid untuk melacak pid anak, Anda kemudian dapat membuat skrip yang memeriksa modtime dari file pid dan membunuh / merespons proses yang diperlukan. Kemudian cukup letakkan skrip di crontab untuk dijalankan pada sekitar periode yang Anda butuhkan.
Beri tahu saya jika Anda membutuhkan detail lebih lanjut. Jika itu kedengarannya tidak sesuai dengan kebutuhan Anda, bagaimana dengan pemula?
sumber
Salah satu caranya adalah dengan menjalankan program dalam subkulit, dan berkomunikasi dengan subkulit melalui pipa bernama dengan
read
perintah. Dengan cara ini Anda dapat memeriksa status keluar dari proses yang sedang berjalan dan mengkomunikasikannya kembali melalui pipa.Berikut adalah contoh penghentian
yes
perintah setelah 3 detik. Ia mendapat PID dari proses menggunakanpgrep
(mungkin hanya bekerja di Linux). Ada juga beberapa masalah dengan menggunakan pipa dalam proses membuka pipa untuk membaca akan menggantung sampai juga dibuka untuk menulis, dan sebaliknya. Jadi untuk mencegahread
perintah menggantung, saya sudah "terjepit" membuka pipa untuk dibaca dengan subkulit latar belakang. (Cara lain untuk mencegah pembekuan untuk membuka pipa baca-tulis, yaituread -t 5 <>finished.pipe
- namun, itu juga mungkin tidak berfungsi kecuali dengan Linux.)sumber
Berikut adalah upaya yang mencoba untuk menghindari membunuh proses setelah itu sudah keluar, yang mengurangi kemungkinan membunuh proses lain dengan ID proses yang sama (walaupun mungkin mustahil untuk menghindari kesalahan semacam ini sepenuhnya).
Gunakan like
run_with_timeout 3 sleep 10000
, yang berjalansleep 10000
tetapi mengakhirinya setelah 3 detik.Ini seperti jawaban lain yang menggunakan proses timeout latar belakang untuk membunuh proses anak setelah penundaan. Saya pikir ini hampir sama dengan jawaban diperpanjang Dan ( https://stackoverflow.com/a/5161274/1351983 ), kecuali shell timeout tidak akan dibunuh jika sudah berakhir.
Setelah program ini berakhir, masih akan ada beberapa proses "sleep" yang berjalan, tetapi tidak berbahaya.
Ini mungkin solusi yang lebih baik daripada jawaban saya yang lain karena tidak menggunakan fitur shell non-portabel
read -t
dan tidak menggunakanpgrep
.sumber
(exec sh -c "$*") &
dansh -c "$*" &
? Secara khusus, mengapa menggunakan yang pertama dan bukan yang terakhir?Inilah jawaban ketiga yang saya kirimkan di sini. Yang ini menangani interupsi sinyal dan membersihkan proses latar belakang saat
SIGINT
diterima. Ia menggunakan$BASHPID
danexec
trik yang digunakan dalam jawaban atas untuk mendapatkan PID dari suatu proses (dalam hal ini$$
dalamsh
doa). Ia menggunakan FIFO untuk berkomunikasi dengan subkulit yang bertanggung jawab atas pembunuhan dan pembersihan. (Ini seperti pipa di jawaban kedua saya , tetapi memiliki pipa bernama berarti penangan sinyal juga bisa menulis ke dalamnya.)Saya sudah mencoba menghindari kondisi balapan sejauh yang saya bisa. Namun, satu sumber kesalahan yang tidak bisa saya hapus adalah ketika proses berakhir dekat waktu yang sama dengan batas waktu. Misalnya,
run_with_timeout 2 sleep 2
ataurun_with_timeout 0 sleep 0
. Bagi saya, yang terakhir memberikan kesalahan:karena sedang mencoba untuk membunuh proses yang sudah keluar dengan sendirinya.
sumber