Shell: apakah mungkin untuk menunda perintah tanpa menggunakan `sleep`?
21
Apakah ada pengganti, alternatif, atau trik bash untuk menunda perintah tanpa menggunakan sleep? Misalnya, menjalankan perintah di bawah tanpa benar-benar menggunakan sleep:
Tidak ada alasan sebenarnya selain rasa ingin tahu. Saya pikir akan menarik untuk mempelajari beberapa solusi alternatif. Saya pikir atmungkin satu, tetapi saya tidak dapat menemukan contoh penggunaan.
user321697
1
@ user321697 "at" adalah untuk menjadwalkan pekerjaan tunggal. mereka dieksekusi oleh layanan atd, sehingga mereka tidak akan menjeda skrip shell Anda. satu use case untuk at adalah untuk membuatnya melakukan sesuatu pada waktu yang ditentukan (async) dan membuat file marker ketika sudah selesai, sementara skrip Anda sedang menunggu file itu muncul dalam loop sementara. Anda dapat mencapai efek yang sama dengan menjadwalkan pekerjaan untuk mengirim skrip Anda SIGCONT dan kemudian membekukan skrip Anda dengan mengirimkan sendiri SIGSTOP.
Grega Bremec
1
Saya datang ke sini mengharapkan semua orang menyarankan spinlock. Saya terkejut dengan semua jawaban.
Daan van Hoek
3
Re: "Keingintahuan" - di unix.stackexchange.com/help/dont-ask , perhatikan persyaratan bahwa "Anda hanya boleh mengajukan pertanyaan praktis, yang dapat dijawab berdasarkan masalah aktual yang Anda hadapi. " - bahwa ini telah berhasil diterima meskipun bertentangan dengan pedoman yang membuatnya menjadi pengecualian yang agak jarang.
Charles Duffy
Jawaban:
17
Anda memiliki alternatif untuk sleep: Mereka adalah atdan cron. Berlawanan dengan sleepini, Anda perlu menyediakan waktu untuk menjalankannya.
Pastikan atdlayanan berjalan dengan mengeksekusi service atd status.
Sekarang misalkan tanggal 11:17 UTC; jika Anda perlu untuk menjalankan perintah di 11:25 UTC, sintaks adalah: echo "This is a test" | at 11:25.
Sekarang perlu diingat bahwa atdsecara default tidak akan mencatat penyelesaian pekerjaan. Untuk lebih banyak merujuk tautan ini . Lebih baik aplikasi Anda memiliki pencatatan sendiri.
Anda dapat menjadwalkan pekerjaan di cron, untuk referensi lebih lanjut: man cronuntuk melihat opsi-opsi atau crontab -euntuk menambah pekerjaan baru. /var/log/crondapat diperiksa untuk info tentang eksekusi pada pekerjaan.
FYI sleep system call menunda eksekusi saat ini dan menjadwalkannya dengan argumen yang diteruskan ke sana.
EDIT:
Seperti yang disebutkan @ Gayus, Anda juga dapat menambahkan menit waktu untuk atmemberi perintah. Tetapi katakanlah waktunya sudah 12:30:30dan sekarang Anda menjalankan scheduler now +1 minutes. Meskipun 1 menit, yang diterjemahkan menjadi 60 detik telah ditentukan, attetapi tidak benar-benar menunggu sampai 12:31:30untuk mengeksekusi pekerjaan, melainkan mengeksekusi pekerjaan di 12:31:00. Unit waktu dapat minutes, hours, days, or weeks. Untuk referensi lebih lanjutman at
Ini tidak benar, Anda dapat menjadwalkan suatu pekerjaan untuk mengatakan sekarang +1 menit, untuk berjalan dalam waktu beberapa menit
Gayus
29
Dengan bashbuiltin, Anda dapat melakukan:
coproc read -t 10&& wait "$!"|| true
Tidur selama 10 detik tanpa menggunakan sleep. Yang coprocharus dibuat agar readstdin adalah pipa tempat tidak akan ada yang keluar. || truekarena waitstatus keluar akan mencerminkan pengiriman SIGALRM yang akan menyebabkan shell keluar jika errexitopsi disetel.
Dalam cangkang lain:
mkshdan ksh93memiliki sleepbuilt-in, tidak ada gunanya menggunakan apa pun di sana (meskipun mereka berdua juga mendukung read -t).
zshjuga mendukung read -t, tetapi juga memiliki pembungkus bawaan select(), sehingga Anda juga dapat menggunakan:
Apakah Anda akan mempertimbangkannya read -t 10 < /dev/zero || true?
Jeff Schaller
5
@ JeffSchaller Saya akan menghindarinya karena itu adalah lingkaran sibuk.
Stéphane Chazelas
@ StéphaneChazelas Saya tidak akan berharap itu menjadi loop sibuk - Saya berharap shell readakan diimplementasikan menggunakan select (2) atau yang serupa (menyiratkan bahwa read-with-timeout akan menjadi jawaban yang baik untuk pertanyaan ini). Saya mengungkapkan keterkejutan alih-alih bertentangan dengan Anda, tetapi dapatkah Anda mengarahkan diskusi lebih lanjut tentang ini?
Norman Grey
5
@NormanGray, /dev/zeroadalah file yang berisi jumlah data tak terbatas (NUL byte). Jadi readakan membaca sebanyak mungkin selama 10 detik itu. Untungnya, dalam kasus bashyang tidak mendukung penyimpanan byte NUL dalam variabelnya, itu tidak akan menggunakan memori apa pun, tetapi itu masih akan memakan banyak sumber daya CPU.
Stéphane Chazelas
1
@NormanGray, jika dijalankan dari terminal, /dev/stdoutakan menjadi perangkat tty, sehingga akan memiliki efek samping (seperti menghentikan skrip jika dijalankan di latar belakang) dan akan kembali jika pengguna menekan masuk misalnya. read -t 10 /dev/stdout | :akan bekerja di Linux, tetapi hanya di Linux, sementara coprocharus bekerja terlepas dari OS.
Stéphane Chazelas
7
Beberapa ide lain.
top -d10 -n2 >/dev/null
vmstat 102>/dev/null
sar 101>/dev/null
timeout 10s tail -f /dev/null
Anda "mencuri" ide saya tentang timelimit / timeout .... +1
Rui F Ribeiro
1
Ohhhh, terima kasih, saya berada dalam situasi tanpa tidur, top luar biasa!
Fire-Dragon-DoL
6
Karena ada jawaban yang menyarankan untuk menggunakan non-standar -t delaypilihan read, di sini adalah cara untuk melakukan waktunya-out dibaca di shell standar:
{ ss=`stty -g`; stty -icanon min 0 time 20; read foo; stty "$ss";}
Argumen untuk stty timeberada dalam sepersepuluh detik.
Itu pada dasarnya akan berhenti untuk jangka waktu berkisar antara 9 dan 10 detik (karena bug dibash ; zshdan mkshmemiliki masalah yang sama tetapi telah diperbaiki sejak)
Stéphane Chazelas
7
Cara yang baik untuk membuat panas.
ctrl-alt-delor
6
tidak akan menjadi pertama kalinya saya dituduh penuh dengan udara panas! :)
Ini tidak akan terjadi jika proses perlu menjalankan interaksi bebas atau di latar belakang kan?
ss_iwe
Benar: Tapi itu bukan salah satu persyaratan OP sesuai pertanyaan awal, jadi masih merupakan jawaban yang valid ... ;-)> :-)
Fabby
1
OP secara khusus memberikan contoh (dengan sleep) dan meminta alternatif yang setara tanpa. Jadi readjangan parse, maaf. ;)
AnoE
@AnoE Stéphane jawaban tentu saja yang terbaik, milikku hanya yang tertua --- press «enter» to continue --- ;-)
Fabby
4
Kembali pada zaman mikrokomputer yang menjalankan BASIC, penundaan biasanya diselesaikan dengan loop kosong:
FOR I = 1 TO 10000:NEXT
Prinsip yang sama dapat digunakan untuk memasukkan penundaan dalam skrip shell:
COUNTER=0; while [ $COUNTER -lt 10000 ]; do :; let COUNTER=COUNTER+1; done
Tentu saja, masalah dengan pendekatan ini adalah bahwa panjang penundaan akan bervariasi dari mesin ke mesin sesuai dengan kecepatan prosesornya (atau bahkan pada mesin yang sama di bawah beban yang berbeda). Tidak seperti sleepitu, ia mungkin juga akan memaksimalkan CPU Anda (atau salah satu dari intinya).
Delay-loop adalah ide yang mengerikan untuk apa pun kecuali yang paling singkat dari tidur (beberapa nanodetik atau siklus clock pada driver perangkat) pada CPU modern yang dapat menjalankan OS seperti Unix. yaitu tidur yang begitu singkat sehingga Anda tidak dapat menggunakan CPU untuk melakukan hal lain sambil menunggu, seperti menjadwalkan proses lain atau memasuki kondisi tidur rendah daya sebelum terbangun dengan penghenti waktu. Frekuensi CPU dinamis membuat bahkan tidak mungkin untuk mengkalibrasi loop tunda untuk hitungan per detik, kecuali sebagai penundaan minimum yang berpotensi tidur jauh lebih lama pada kecepatan clock rendah sebelum naik.
Peter Cordes
Komputer kuno memiliki konsumsi daya yang jauh lebih sedikit bergantung pada beban kerja. CPU modern perlu secara dinamis mematikan bagian-bagian berbeda dari chip sebanyak mungkin untuk tidak meleleh (misalnya mematikan bagian-bagian FPU atau unit eksekusi SIMD sementara hanya kode integer yang berjalan, atau setidaknya gerbang sinyal jam ke bagian-bagian chip) yang tidak perlu beralih). Dan memasuki kondisi tidur berdaya rendah saat idle (alih-alih berputar dalam putaran tak terbatas menunggu penghentian waktu) juga lebih baru daripada komputer kuno yang Anda sebutkan.
Maaf untuk mengembalikan suntingan Anda ke Q: Anda mengubah tujuan utama pertanyaan OPs yang akan membatalkan jawaban paling sederhana dari semua ... ¯ \ _ (ツ) _ / ¯
Fabby
3
Klasik dari Land of Windows and Batches:
ping -c 11 localhost >/dev/null && echo "This is a test"
Kesalahan konfigurasi sistem firewall atau nama mungkin menimbulkan kesulitan tambahan yang signifikan.
spektrum
1
127.0.0.1 ... @spectras
AnoE
1
Untungnya tidak lagi diperlukan, karena Windows sekarang mendukung tidur secara native.
Baldrickk
1
@AnoE> memecahkan bagian sistem nama, bukan bagian firewall. Meskipun tidak umum, dapat dikonfigurasi untuk secara diam-diam menjatuhkan ping ke antarmuka lokal. Itu akan menyebabkan ping menunggu lebih lama.
spektrum
+1 untuk kenangan "suka"
AC
0
Jika Anda ingin menunggu baris baru dalam file secara interaktif, maka
tail -f
.
Menunggu perubahan pada sistem file? Kemudian gunakan mis
inotify / inoticoming
.
Dan ada opsi lain, tergantung pada apa yang Anda maksud dengan "tunggu".
sleep
?at
mungkin satu, tetapi saya tidak dapat menemukan contoh penggunaan.Jawaban:
Anda memiliki alternatif untuk
sleep
: Mereka adalahat
dancron
. Berlawanan dengansleep
ini, Anda perlu menyediakan waktu untuk menjalankannya.Pastikan
atd
layanan berjalan dengan mengeksekusiservice atd status
.Sekarang misalkan tanggal 11:17 UTC; jika Anda perlu untuk menjalankan perintah di 11:25 UTC, sintaks adalah:
echo "This is a test" | at 11:25
.Sekarang perlu diingat bahwa
atd
secara default tidak akan mencatat penyelesaian pekerjaan. Untuk lebih banyak merujuk tautan ini . Lebih baik aplikasi Anda memiliki pencatatan sendiri.Anda dapat menjadwalkan pekerjaan di
cron
, untuk referensi lebih lanjut:man cron
untuk melihat opsi-opsi ataucrontab -e
untuk menambah pekerjaan baru./var/log/cron
dapat diperiksa untuk info tentang eksekusi pada pekerjaan.FYI
sleep system call
menunda eksekusi saat ini dan menjadwalkannya dengan argumen yang diteruskan ke sana.EDIT:
Seperti yang disebutkan @ Gayus, Anda juga dapat menambahkan menit waktu untuk
at
memberi perintah. Tetapi katakanlah waktunya sudah12:30:30
dan sekarang Anda menjalankan schedulernow +1 minutes
. Meskipun 1 menit, yang diterjemahkan menjadi 60 detik telah ditentukan,at
tetapi tidak benar-benar menunggu sampai12:31:30
untuk mengeksekusi pekerjaan, melainkan mengeksekusi pekerjaan di12:31:00
. Unit waktu dapatminutes, hours, days, or weeks
. Untuk referensi lebih lanjutman at
misalnya:
echo "ls" | at now +1 minutes
sumber
Dengan
bash
builtin, Anda dapat melakukan:Tidur selama 10 detik tanpa menggunakan
sleep
. Yangcoproc
harus dibuat agarread
stdin adalah pipa tempat tidak akan ada yang keluar.|| true
karenawait
status keluar akan mencerminkan pengiriman SIGALRM yang akan menyebabkan shell keluar jikaerrexit
opsi disetel.Dalam cangkang lain:
mksh
danksh93
memilikisleep
built-in, tidak ada gunanya menggunakan apa pun di sana (meskipun mereka berdua juga mendukungread -t
).zsh
juga mendukungread -t
, tetapi juga memiliki pembungkus bawaanselect()
, sehingga Anda juga dapat menggunakan:Jika yang Anda inginkan adalah menjadwalkan hal-hal yang akan dijalankan dari sesi shell interaktif, lihat juga
zsh/sched
modul dizsh
.sumber
read -t 10 < /dev/zero || true
?read
akan diimplementasikan menggunakan select (2) atau yang serupa (menyiratkan bahwa read-with-timeout akan menjadi jawaban yang baik untuk pertanyaan ini). Saya mengungkapkan keterkejutan alih-alih bertentangan dengan Anda, tetapi dapatkah Anda mengarahkan diskusi lebih lanjut tentang ini?/dev/zero
adalah file yang berisi jumlah data tak terbatas (NUL byte). Jadiread
akan membaca sebanyak mungkin selama 10 detik itu. Untungnya, dalam kasusbash
yang tidak mendukung penyimpanan byte NUL dalam variabelnya, itu tidak akan menggunakan memori apa pun, tetapi itu masih akan memakan banyak sumber daya CPU./dev/stdout
akan menjadi perangkat tty, sehingga akan memiliki efek samping (seperti menghentikan skrip jika dijalankan di latar belakang) dan akan kembali jika pengguna menekan masuk misalnya.read -t 10 /dev/stdout | :
akan bekerja di Linux, tetapi hanya di Linux, sementaracoproc
harus bekerja terlepas dari OS.Beberapa ide lain.
sumber
Karena ada jawaban yang menyarankan untuk menggunakan non-standar
-t delay
pilihanread
, di sini adalah cara untuk melakukan waktunya-out dibaca di shell standar:Argumen untuk
stty time
berada dalam sepersepuluh detik.sumber
Menggunakan variabel bawaan bash
$SECONDS
dan loop sibuk:sumber
bash
;zsh
danmksh
memiliki masalah yang sama tetapi telah diperbaiki sejak)trik tertua dalam buku:
Tekan saja Enterdan itu akan terus!
sumber
sleep
) dan meminta alternatif yang setara tanpa. Jadiread
jangan parse, maaf. ;)--- press «enter» to continue ---
;-)Kembali pada zaman mikrokomputer yang menjalankan BASIC, penundaan biasanya diselesaikan dengan loop kosong:
FOR I = 1 TO 10000:NEXT
Prinsip yang sama dapat digunakan untuk memasukkan penundaan dalam skrip shell:
COUNTER=0; while [ $COUNTER -lt 10000 ]; do :; let COUNTER=COUNTER+1; done
Tentu saja, masalah dengan pendekatan ini adalah bahwa panjang penundaan akan bervariasi dari mesin ke mesin sesuai dengan kecepatan prosesornya (atau bahkan pada mesin yang sama di bawah beban yang berbeda). Tidak seperti
sleep
itu, ia mungkin juga akan memaksimalkan CPU Anda (atau salah satu dari intinya).sumber
Tidak ada built-in, yang melakukan hal yang sama
sleep
(kecualisleep
ada built-in). Namun ada beberapa perintah lain yang akan menunggu.Beberapa di antaranya.
at
dancron
: digunakan untuk menjadwalkan tugas pada waktu tertentu.inotifywait
: digunakan untuk menunggu file, atau file yang akan diubah / dihapus / ditambahkan / dllsumber
at
?cron
menyimpan tugascrontab
, kan? Di manaat
menyimpan data yang dijadwalkan?Klasik dari Land of Windows and Batches:
sumber
Jika Anda ingin menunggu baris baru dalam file secara interaktif, maka
.Menunggu perubahan pada sistem file? Kemudian gunakan mis
.Dan ada opsi lain, tergantung pada apa yang Anda maksud dengan "tunggu".
sumber