Saya memiliki skrip shell itu membaca dari input standar . Dalam keadaan yang jarang terjadi, tidak akan ada yang siap memberikan masukan, dan skrip harus waktu habis . Dalam hal batas waktu, skrip harus menjalankan beberapa kode pembersihan. Apa cara terbaik untuk melakukannya?
Skrip ini harus sangat portabel , termasuk ke sistem unix abad ke-20 tanpa kompiler C dan ke perangkat tertanam yang menjalankan busybox, jadi Perl, bash, bahasa yang dikompilasi, dan bahkan POSIX.2 lengkap tidak dapat diandalkan. Khususnya, $PPID
, read -t
dan jebakan yang sesuai dengan POSIX tidak tersedia. Menulis ke file sementara juga dikecualikan; skrip mungkin berjalan meskipun semua sistem file dipasang hanya-baca.
Untuk mempersulit, saya juga ingin skripnya cukup cepat ketika waktu tidak habis. Secara khusus, saya juga menggunakan skrip di Windows (terutama di Cygwin), di mana fork dan exec sangat rendah, jadi saya ingin meminimalkan penggunaannya.
Singkatnya, saya punya
trap cleanup 1 2 3 15
foo=`cat`
dan saya ingin menambahkan batas waktu. Saya tidak dapat mengganti cat
dengan read
built-in. Jika waktu habis, saya ingin menjalankan cleanup
fungsi.
Latar Belakang:skrip ini menebak pengkodean terminal dengan mencetak beberapa karakter 8-bit dan membandingkan posisi kursor sebelum dan sesudah. Awal skrip menguji bahwa stdout terhubung ke terminal yang didukung, tetapi terkadang lingkungannya berbohong (mis. plink
set TERM=xterm
meskipun disebut dengan TERM=dumb
). Bagian skrip yang relevan 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, itu dimatikan dan skrip menjalankan cleanup
fungsi?
Jawaban yang Diterima:
Bagaimana dengan ini:
foo=`{ { cat 1>&3; kill 0; } | { sleep 2; kill 0; } } 3>&1`
Yaitu:jalankan perintah penghasil output dan sleep
dalam grup proses yang sama, grup proses hanya untuk mereka. Perintah mana pun yang kembali lebih dulu membunuh seluruh grup proses.
Apakah ada yang bertanya-tanya:Ya, pipa tidak digunakan; itu dilewati menggunakan pengalihan. Satu-satunya tujuannya adalah agar shell menjalankan dua proses dalam grup proses yang sama.
Terkait:Skrip untuk mengecilkan dan mengompresi gambar disk DMG tampaknya tidak berfungsi dengan baik dalam skenario?Seperti yang ditunjukkan Gilles dalam komentarnya, ini tidak akan berfungsi dalam skrip shell karena proses skrip akan dihentikan bersama dengan dua subproses.
Salah satu cara¹ untuk memaksa perintah dijalankan dalam grup proses terpisah adalah dengan memulai shell interaktif baru:
#!/bin/sh
foo=`sh -ic '{ cat 1>&3; kill 0; } | { sleep 2; kill 0; }' 3>&1 2>/dev/null`
[ -n "$foo" ] && echo got: "$foo" || echo timeouted
Tapi mungkin ada peringatan dengan ini (misalnya ketika stdin bukan tty?). Pengalihan stderr ada untuk menghilangkan pesan "Dihentikan" saat shell interaktif dimatikan.
Diuji dengan zsh
,bash
dan dash
. Tapi bagaimana dengan orang tua?
B98 menyarankan perubahan berikut, bekerja pada Mac OS X, dengan GNU bash 3.2.57, atau Linux dengan tanda hubung:
foo=`sh -ic 'exec 3>&1 2>/dev/null; { cat 1>&3; kill 0; } | { sleep 2; kill 0; }'`
–