Saya memiliki skrip shell yang membaca dari input standar . Dalam keadaan yang jarang terjadi, tidak akan ada orang yang siap memberikan masukan, dan skrip harus berhenti . Dalam hal batas waktu, skrip harus menjalankan beberapa kode pembersihan. Apa cara terbaik untuk melakukan itu?
Skrip ini harus sangat portabel , termasuk ke sistem unix abad ke-20 tanpa kompiler C dan ke perangkat tertanam yang menjalankan busybox, sehingga Perl, bash, bahasa yang dikompilasi, dan bahkan POSIX.2 lengkap tidak dapat diandalkan. Secara khusus, $PPID
, read -t
perangkap dan sempurna POSIX-compliant tidak tersedia. Menulis ke file sementara juga dikecualikan; skrip dapat berjalan bahkan jika semua sistem file dipasang hanya-baca.
Hanya untuk membuat segalanya lebih sulit, saya juga ingin skrip menjadi cukup cepat ketika tidak ada waktu habis. Secara khusus, saya juga menggunakan script di Windows (terutama di Cygwin), di mana garpu dan exec sangat rendah, jadi saya ingin menjaga penggunaannya seminimal mungkin.
Singkatnya, saya punya
trap cleanup 1 2 3 15
foo=`cat`
dan saya ingin menambahkan batas waktu. Saya tidak bisa mengganti cat
dengan read
built-in. Dalam hal timeout, saya ingin menjalankan cleanup
fungsinya.
Latar Belakang: skrip ini menebak pengodean terminal dengan mencetak beberapa karakter 8-bit dan membandingkan posisi kursor sebelum dan sesudah. Awal tes skrip yang stdout terhubung ke terminal yang didukung, tetapi kadang-kadang lingkungan berbohong (misalnya plink
mengatur TERM=xterm
bahkan jika itu dipanggil denganTERM=dumb
). Bagian yang relevan dari skrip terlihat seperti ini:
text='Éé' # UTF-8; shows up as Ãé on a latin1 terminal
csi='␛['; dsr_cpr="${csi}6n"; dsr_ok="${csi}5n" # ␛ is an escape character
stty_save=`stty -g`
cleanup () { stty "$stty_save"; }
trap 'cleanup; exit 120' 0 1 2 3 15 # cleanup code
stty eol 0 eof n -echo # Input will end with `0n`
# echo-n is a function that outputs its argument without a newline
echo-n "$dsr_cpr$dsr_ok" # Ask the terminal to report the cursor position
initial_report=`tr -dc \;0123456789` # Expect ␛[42;10R␛[0n for y=42,x=10
echo-n "$text$dsr_cpr$dsr_ok"
final_report=`tr -dc \;0123456789`
cleanup
# Compute and return initial_x - final_x
Bagaimana saya bisa memodifikasi skrip sehingga jika tr
belum membaca input apa pun setelah 2 detik, skrip tersebut dimatikan dan skrip mengeksekusi cleanup
fungsinya?
Jawaban:
Bagaimana dengan ini:
Yaitu: jalankan perintah penghasil keluaran dan
sleep
dalam grup proses yang sama, grup proses hanya untuk mereka. Perintah apa pun yang mengembalikan pertama membunuh seluruh proses grup.Adakah yang bertanya-tanya: Ya, pipa itu tidak digunakan; itu dilewati menggunakan pengalihan. Tujuan satu-satunya adalah agar shell menjalankan dua proses dalam grup proses yang sama.
Seperti yang ditunjukkan Gilles dalam komentarnya, ini tidak akan berfungsi dalam shell script karena proses script akan terbunuh bersama dengan dua subproses.
Salah satu cara¹ untuk memaksa perintah untuk dijalankan dalam grup proses yang terpisah adalah memulai shell interaktif baru:
Tetapi mungkin ada peringatan dengan ini (misalnya ketika stdin bukan tty?). Pengarahan stderr ada di sana untuk menyingkirkan pesan "Dihentikan" ketika shell interaktif terbunuh.
Diuji dengan
zsh
,bash
dandash
. Tapi bagaimana dengan oldies?B98 menyarankan perubahan berikut, bekerja pada Mac OS X, dengan GNU bash 3.2.57, atau Linux dengan tanda hubung:
-
1. selain
setsid
yang tampaknya non-standar.sumber
kill 0
akhirnya membunuh penelepon skrip juga. Apakah ada cara portabel untuk memaksa pipa ke dalam kelompok prosesnya sendiri?setprgp()
tanpasetsid
untuk saat :-(Anda sudah menjebak 15 (versi numerik
SIGTERM
, yaitu apa yangkill
dikirim kecuali dikatakan sebaliknya), jadi Anda seharusnya sudah siap. Yang mengatakan, jika Anda melihat pra-POSIX, perlu diketahui bahwa fungsi shell mungkin tidak ada (mereka berasal dari shell System V).sumber
cat
keluar. Saya sudah bereksperimen sedikit tetapi tidak menemukan apa pun yang saya puas sejauh ini.$!
, saya pikir beberapa mesin yang saya gunakan jarang tidak memiliki kontrol pekerjaan, apakah$!
tersedia secara universal?bash
spesifik yang pernah saya lakukan melibatkan pelecehan-o monitor
. Saya sedang berpikir dalam hal kerang yang benar-benar kuno ketika saya menulis itu (itu berhasil di v7). Yang mengatakan, saya pikir Anda dapat melakukan salah satu dari dua hal lain: (1) latar belakang "apa pun" danwait $!
, atau (2) juga mengirimSIGCLD
/SIGCHLD
... tetapi pada mesin yang cukup lama yang terakhir adalah tidak ada atau tidak dapat diangkut (yang pertama adalah Sistem III / V, yang terakhir BSD, dan V7 tidak punya).$!
kembali ke V7 setidaknya, dan tentu saja mendahuluish
-seperti yang tahu apa-apa tentang kontrol pekerjaan (pada kenyataannya, untuk waktu yang lama/bin/sh
di BSD tidak melakukan kontrol pekerjaan; Anda harus berlaricsh
untuk mendapatkannya - tetapi$!
ada di sana ).$!
.Meskipun coretuils pada versi 7.0 termasuk perintah batas waktu Anda telah menyebutkan beberapa lingkungan yang tidak akan memilikinya. Untungnya pixelbeat.org memiliki skrip waktu habis yang ditulis
sh
.Saya telah menggunakannya sebelumnya pada beberapa kesempatan dan ini bekerja dengan sangat baik.
http://www.pixelbeat.org/scripts/timeout ( Catatan: Skrip di bawah ini sedikit dimodifikasi dari yang ada di pixelbeat.org, lihat komentar di bawah jawaban ini.)
sumber
</dev/stdin
adalah no-op.</dev/tty
akan memungkinkannya untuk membaca dari terminal, yang cukup baik untuk kasus penggunaan saya.Bagaimana dengan (ab) gunakan NC untuk ini
Suka;
Atau digulung menjadi satu baris perintah;
Versi terakhir, walaupun terlihat aneh sebenarnya tidak berfungsi ketika saya mengujinya pada sistem linux - tebakan terbaik saya adalah bahwa itu harus bekerja pada sistem apa pun, dan jika tidak variasi redirection output dapat memecahkan masalah portabilitas. manfaat di sini adalah tidak ada proses latar belakang yang terlibat.
sumber
nc
beberapa kotak lama Unix, atau pada banyak Linux yang tertanam.Cara lain untuk menjalankan pipeline di grup prosesnya sendiri adalah dengan menjalankan
sh -c '....'
pseudo-terminal menggunakanscript
perintah (yang secara implisit menerapkansetsid
fungsi).sumber
script
beberapa kotak lama Unix, atau pada banyak Linux yang tertanam.Jawabannya di https://unix.stackexchange.com/a/18711 sangat bagus.
Saya ingin mencapai hasil yang serupa, tetapi tanpa harus secara eksplisit memanggil shell lagi karena saya ingin memanggil fungsi shell yang ada.
Menggunakan bash, dimungkinkan untuk melakukan hal berikut:
Jadi misalkan saya sudah memiliki fungsi shell
f
:Menjalankan ini saya melihat:
sumber
sumber