Jawaban untuk perintah baris perintah ini untuk secara otomatis membunuh perintah setelah waktu tertentu
mengusulkan metode 1-baris untuk menghentikan perintah yang sudah berjalan lama dari baris perintah bash:
( /path/to/slow command with options ) & sleep 5 ; kill $!
Tapi mungkin saja perintah "jangka panjang" yang diberikan bisa selesai lebih awal dari batas waktu. (Sebut saja "perintah yang biasanya berjalan lama tapi kadang-kadang cepat", atau tlrbsf untuk bersenang-senang.)
Jadi pendekatan 1-liner yang bagus ini memiliki beberapa masalah. Pertama, sleep
tidak bersyarat, sehingga menetapkan batas bawah yang tidak diinginkan pada waktu yang dibutuhkan untuk menyelesaikan urutan. Pertimbangkan 30s atau 2m atau bahkan 5m untuk tidur, ketika perintah tlrbsf selesai dalam 2 detik - sangat tidak diinginkan. Kedua, kill
tidak bersyarat, sehingga urutan ini akan mencoba untuk membunuh proses yang tidak berjalan dan mengeluh tentang hal itu.
Begitu...
Apakah ada cara untuk menghentikan perintah ( "tlrbsf" ) yang biasanya berjalan lama tapi kadang-kadang cepat
- memiliki implementasi bash (pertanyaan lain sudah memiliki jawaban Perl dan C)
- akan berakhir di bagian paling awal dari keduanya: penghentian program tlrbsf , atau batas waktu telah berlalu
- tidak akan membunuh proses yang tidak ada / tidak berjalan (atau, opsional: tidak akan mengeluh tentang pembunuhan yang buruk)
- tidak harus menjadi 1-liner
- dapat berjalan di bawah Cygwin atau Linux
... dan, untuk poin bonus, jalankan perintah tlrbsf di latar depan dan 'sleep' atau proses tambahan apa pun di latar belakang, sehingga stdin / stdout / stderr dari perintah tlrbsf dapat dialihkan, sama seperti jika telah lari langsung?
Jika demikian, silakan bagikan kode Anda. Jika tidak, tolong jelaskan mengapa.
Saya telah menghabiskan beberapa waktu mencoba meretas contoh yang disebutkan di atas tetapi saya mencapai batas kemampuan bash saya.
sumber
timeout
utilitas gnu ?timeout
bagus! Anda bahkan dapat menggunakan beberapa perintah (skrip multi-baris): stackoverflow.com/a/61888916/658497Jawaban:
Saya pikir inilah tepatnya yang Anda minta:
http://www.bashcookbook.com/bashinfo/source/bash-4.0/examples/scripts/timeout3
sumber
Anda mungkin mencari
timeout
perintah di coreutils. Karena ini adalah bagian dari coreutils, secara teknis ini adalah solusi C, tetapi masih coreutils.info timeout
untuk lebih jelasnya. Ini sebuah contoh:sumber
gtimeout
brew install coreutils
, dan kemudian Anda dapat menggunakannyagtimeout
.Solusi ini berfungsi terlepas dari mode bash monitor. Anda dapat menggunakan sinyal yang tepat untuk mengakhiri perintah_Anda
Pengamat membunuh perintah_Anda setelah batas waktu diberikan; skrip menunggu tugas yang lambat dan menghentikan pengamat. Catat itu
wait
tidak bekerja dengan proses yang merupakan anak-anak dari shell yang berbeda.Contoh:
sumber
wait
mengembalikan status keluar dari proses yang ditunggu. Jadi, jika perintah Anda benar-benar keluar dalam waktu yang ditentukan tetapi dengan status keluar bukan nol maka logika di sini akan berperilaku seperti waktu habis, yaitu cetakyour_command interrupted
. Sebaliknya Anda bisa melakukanwait
tanpaif
dan kemudian memeriksa apakah$watcher
pid masih ada, jika tidak maka Anda tahu Anda tidak kehabisan waktu.kill
dalam satu kasus tetapipkill
dalam kasus lain. Saya perlu menggunakanpkill
keduanya untuk membuat ini berfungsi dengan benar. Saya berharap bahwa jika Anda memasukkan perintah()
, maka Anda harus menggunakanpkill
untuk membunuhnya. Tetapi mungkin ini bekerja secara berbeda jika hanya ada satu perintah di dalam()
.Ini dia:
Anda dapat mengubah
SIGINT
dan10
sesuai keinginan;)sumber
coreutils
paket di FreeBSD.Anda dapat melakukan ini sepenuhnya dengan
bash 4.3
dan di atas:_timeout 5 longrunning_command args
{ _timeout 5 producer || echo KABOOM $?; } | consumer
producer | { _timeout 5 consumer1; consumer2; }
Contoh:
{ while date; do sleep .3; done; } | _timeout 5 cat | less
Membutuhkan Bash 4.3 untuk
wait -n
Jika Anda tidak memerlukan kode pengembalian, ini dapat dibuat lebih sederhana:
Catatan:
Sebenarnya Anda tidak perlu
;
masuk; )
, tetapi itu membuat hal lebih konsisten ke-; }
tas. Danset +b
mungkin bisa dibiarkan begitu saja, tetapi lebih baik aman daripada menyesal.Kecuali untuk
--forground
(mungkin) Anda dapat mengimplementasikan semua variantimeout
dukungan.--preserve-status
memang agak sulit. Ini dibiarkan sebagai latihan untuk pembaca;)Resep ini dapat digunakan "secara alami" dalam cangkang (sealami untuk
flock fd
):Namun, seperti dijelaskan di atas, Anda tidak dapat mengekspor kembali variabel lingkungan ke shell penutup dengan cara ini secara alami.
Edit:
Contoh dunia nyata: Waktu habis
__git_ps1
jika terlalu lama (untuk hal-hal seperti SSHFS-Links lambat):Edit2: Perbaikan Bug. Saya perhatikan itu
exit 137
tidak diperlukan dan membuat_timeout
tidak dapat diandalkan pada saat yang sama.Sunting3:
git
sangat sulit, sehingga perlu trik ganda untuk bekerja dengan memuaskan.Sunting4: Lupa a
_
di pertama_timeout
untuk contoh GIT dunia nyata.sumber
cc. The 'wait' builtin has a new '-n' option to wait for the next child to change status.
Dari: tiswww.case.edu/php/chet/bash/NEWSSaya lebih suka "timelimit", yang memiliki paket setidaknya di debian.
http://devel.ringlet.net/sysutils/timelimit/
Ini sedikit lebih bagus daripada "timeout" coreutils karena ia mencetak sesuatu ketika mematikan proses, dan juga mengirimkan SIGKILL setelah beberapa waktu secara default.
sumber
timelimit -t1 ./a_forking_prog
hanya membunuh satu dari dua proses), tetapi timeout bekerja.Untuk batas waktu
slowcommand
setelah 1 detik:timeout 1 slowcommand || echo "I failed, perhaps due to time out"
Untuk menentukan apakah perintah habis atau gagal karena alasannya sendiri, periksa apakah kode statusnya 124:
Perhatikan bahwa ketika status keluar adalah 124, Anda tidak tahu apakah itu habis karena
timeout
perintah Anda , atau apakah perintah itu sendiri diakhiri karena beberapa logika batas waktu internal sendiri dan kemudian dikembalikan 124. Anda dapat dengan aman berasumsi dalam kedua kasus Namun, batas waktu semacam itu terjadi.sumber
Lihat juga skrip http://www.pixelbeat.org/scripts/timeout yang fungsinya telah diintegrasikan ke dalam coreutils yang lebih baru
sumber
Agak hacky, tetapi berhasil. Tidak berfungsi jika Anda memiliki proses latar depan lainnya (tolong bantu saya memperbaiki ini!)
Sebenarnya, saya pikir Anda dapat membalikkannya, memenuhi kriteria 'bonus' Anda:
sumber
batas waktu mungkin merupakan pendekatan pertama untuk mencoba. Anda mungkin perlu pemberitahuan atau perintah lain untuk mengeksekusi jika itu habis. Setelah sedikit mencari dan bereksperimen, saya membuat skrip bash ini :
sumber
Script sederhana dengan kejelasan kode. Simpan ke
/usr/local/bin/run
:Perintah time out yang berjalan terlalu lama:
Segera berakhir untuk perintah yang melengkapi:
sumber
Jika Anda sudah tahu nama program (mari kita asumsikan
program
) untuk berakhir setelah batas waktu (sebagai contoh3
detik), saya dapat berkontribusi solusi alternatif yang sederhana dan agak kotor:Ini berfungsi dengan baik jika saya memanggil proses benchmark dengan panggilan sistem.
sumber
argv[0]
, mungkin dengan peretasan lain untuk membuat lebih banyak ruang).(sleep 3 && docker stop <container>) &
bekerja dengan baik. Terima kasih!{ sleep 5 && kill -9 $(ps -fe | grep "program" | grep $$ | tr -s " " | cut -d" " -f2); } & SLEEPPID=$!; bash -c "program" && kill -9 $SLEEPPID"
Dengan cara ini, itu akan membunuh hanya pekerjaan di shell saat ini.Ada juga
cratimeout
oleh Martin Cracauer (ditulis dalam C untuk Unix dan sistem Linux).sumber
OS X belum menggunakan bash 4, juga tidak memiliki / usr / bin / timeout, jadi inilah fungsi yang bekerja pada OS X tanpa home-brew atau macports yang mirip dengan / usr / bin / timeout (berdasarkan Tino menjawab). Validasi parameter, bantuan, penggunaan, dan dukungan untuk sinyal lain adalah latihan untuk pembaca.
sumber
Dalam 99% kasus jawabannya adalah BUKAN untuk menerapkan logika batas waktu. Timeout logika dalam hampir setiap situasi tanda peringatan merah bahwa sesuatu yang lain yang salah dan harus diperbaiki bukan .
Apakah proses Anda tergantung atau rusak setelah n detik kadang-kadang? Kemudian cari tahu mengapa dan perbaiki itu sebagai gantinya.
Selain itu, untuk melakukan solusi strager dengan benar, Anda harus menggunakan tunggu "$ SPID" alih-alih fg 1, karena dalam skrip Anda tidak memiliki kontrol pekerjaan (dan mencoba menyalakannya itu bodoh). Selain itu, fg 1 bergantung pada fakta bahwa Anda tidak memulai pekerjaan lain sebelumnya dalam skrip yang merupakan asumsi buruk untuk dibuat.
sumber
Saya dihadapkan dengan masalah untuk mempertahankan konteks shell dan memungkinkan timeout, satu-satunya masalah dengan itu adalah akan menghentikan eksekusi skrip pada timeout - tetapi tidak masalah dengan kebutuhan saya disajikan:
dengan output:
tentu saja saya menganggap ada dir yang dipanggil
scripts
sumber
sumber
Masalah saya mungkin sedikit berbeda: Saya memulai perintah melalui ssh pada mesin jarak jauh dan ingin membunuh shell dan childs jika perintah hang.
Saya sekarang menggunakan yang berikut ini:
Dengan cara ini perintah mengembalikan 255 ketika ada batas waktu atau kode pengembalian perintah jika berhasil
Harap dicatat bahwa proses mematikan dari sesi ssh ditangani berbeda dari shell interaktif. Tetapi Anda juga dapat menggunakan opsi -t untuk ssh untuk mengalokasikan terminal pseudo, sehingga berfungsi seperti shell interaktif
sumber
Ini adalah versi yang tidak bergantung pada proses melahirkan anak - saya membutuhkan skrip mandiri yang menyematkan fungsi ini. Ini juga melakukan jajak pendapat fraksional, sehingga Anda dapat memilih lebih cepat. batas waktu akan lebih disukai - tapi saya terjebak di server lama
sumber
Cara yang sangat sederhana:
dengan pkill (opsi -f ) Anda dapat membunuh perintah spesifik Anda dengan argumen atau menentukan -n untuk menghindari membunuh proses lama.
sumber
Membangun jawaban @ loup ...
Jika Anda ingin menghentikan proses dan mematikan output kill / pid, jalankan:
Ini menempatkan proses latar belakang ke dalam subkulit sehingga Anda tidak melihat output pekerjaan.
sumber
Saya memiliki pekerjaan cron yang memanggil skrip php dan, kadang-kadang, macet di skrip php. Solusi ini sempurna bagi saya.
Saya menggunakan:
sumber
scripttimeout
?