Bagaimana cara tidur selama milidetik dalam bash atau ksh

128

sleep adalah perintah yang sangat populer dan kita dapat mulai tidur dari 1 detik:

# wait one second please 
sleep 1

tapi apa alternatifnya jika saya harus menunggu hanya 0,1 detik atau antara 0,1 hingga 1 detik?

  • komentar: di linux atau OS X sleep 0.XXXberfungsi dengan baik, tetapi pada solaris sleep 0.1atau sleep 0.01- sintaksis ilegal
yael
sumber
2
Bisakah saya bertanya mengapa Anda ingin tidur selama 1 ms?
Tom O'Connor
1
Ya tentu saja, dalam skrip bash saya menambahkan "sleep 1", dalam beberapa baris, tetapi skrip berjalan sangat lambat, jadi setelah beberapa kesimpulan saya menghitung bahwa sleep 0.1 juga membawa hasil yang baik dan lebih cepat. Tentang penundaan, saya perlu keterlambatan dalam rangka untuk mengatasi masalah ssh di skrip bash saya, saya melakukan paralel ssh login ke beberapa mesin dengan harapan dan tanpa penundaan itu tidak akan berfungsi, Seperti yang Anda tahu dari pertanyaan saya, penundaan harus sesuai dengan Linux dan Solaris
yael
3
Apapun solusi yang Anda pilih, perlu diingat bahwa skrip shell tidak akan sangat akurat dalam hal waktu.
scai
Bagaimana kalau melakukan sesuatu yang membutuhkan waktu sangat singkat untuk dieksekusi, tetapi tidak melakukan apa-apa .. sepertiecho "" >/dev/null
Tom O'Connor
Ide bagus tapi bagaimana msec perintah ini diambil? , Saya perlu 0,1 msec, tidak kurang dari itu - :)
yael

Jawaban:

68

Bash memiliki sleep "loadable" yang mendukung pecahan detik, dan menghilangkan overhead perintah eksternal:

$ cd bash-3.2.48/examples/loadables
$ make sleep && mv sleep sleep.so
$ enable -f sleep.so sleep

Kemudian:

$ which sleep
/usr/bin/sleep
$ builtin sleep
sleep: usage: sleep seconds[.fraction]
$ time (for f in `seq 1 10`; do builtin sleep 0.1; done)
real    0m1.000s
user    0m0.004s
sys     0m0.004s

The downside adalah bahwa loadable mungkin tidak disediakan dengan bashbiner Anda , jadi Anda perlu mengkompilasi sendiri seperti yang ditunjukkan (meskipun pada Solaris itu tidak harus sesederhana seperti di atas).

Padabash-4.4 (September 2016) semua loadable sekarang dibangun dan diinstal secara default pada platform yang mendukungnya, meskipun mereka dibangun sebagai file shared-object yang terpisah, dan tanpa .soakhiran. Kecuali jika distro / OS Anda telah melakukan sesuatu yang kreatif, Anda seharusnya dapat melakukannya:

[ -z "$BASH_LOADABLES_PATH" ] &&
  BASH_LOADABLES_PATH=$(pkg-config bash --variable=loadablesdir 2>/dev/null)  
enable -f sleep sleep

(Halaman manual menunjukkan BASH_LOADABLES_PATHdiset secara otomatis, saya menemukan ini bukan kasus dalam distribusi resmi pada 4.4.12. Jika dan ketika diatur dengan benar Anda hanya perlu enable -f filename commandnameseperti yang diperlukan.)

Jika itu tidak cocok, hal termudah berikutnya yang harus dilakukan adalah membangun atau memperoleh sleepdari GNU coreutils, ini mendukung fitur yang diperlukan. sleepPerintah POSIX minimal, versi Solaris lama hanya mengimplementasikannya. Solaris 11 sleep tidak mendukung detik pecahan.

Sebagai upaya terakhir, Anda dapat menggunakan perl(atau skrip lain yang harus Anda tangani) dengan peringatan bahwa menginisialisasi juru bahasa mungkin sebanding dengan waktu tidur yang dimaksudkan:

$ perl -e "select(undef,undef,undef,0.1);"
$ echo "after 100" | tclsh
mr.spuratic
sumber
2
Ah, karena Anda menggunakan expectAnda mungkin hanya bisa menggunakan " after N", di mana N adalah milidetik, langsung di skrip Anda.
mr.spuratic
gunakan usleepseperti @Luis Vazquez dan @sebix write
Ilan.K
Apple MacOS memiliki tidur BSD, yang juga mendukung detik fraksional
roblogic
125

Dokumentasi untuk sleepperintah dari coreutils mengatakan:

Implementasi historis dari tidur mengharuskan angka itu menjadi bilangan bulat, dan hanya menerima argumen tunggal tanpa akhiran. Namun, tidur GNU menerima angka floating point yang sewenang-wenang. Lihat titik Mengambang .

Karenanya Anda dapat menggunakan sleep 0.1, sleep 1.0e-1dan argumen serupa.

scai
sumber
1
lihat komentar saya tentang SOLARIS OS
yael
Apakah Anda mencampur adalah dan tidak ?
scai
lihat pembaruan saya di kuastion
yael
1
Yael, saya pikir masih ada satu terlalu banyak negatif dalam pertanyaan Anda; Anda yakin maksud Anda "bukan sintaksis ilegal"?
MadHatter
misalnya - saya menjalankan solaris 10 ini: # sleep 0.1 sleep: karakter buruk dalam argumen, tentang linux sleep 0.1 berfungsi dengan baik
yael
58

Tidur menerima angka desimal sehingga Anda dapat memecahnya seperti ini:

1/2 detik

 sleep 0.5

1/100 detik

sleep 0.01

Jadi untuk milidetik yang Anda inginkan

sleep 0.001
colealtdelete
sumber
4
Anda juga dapat menjatuhkan nol di depan sebelum titik desimal. misalnya. sleep .5
Mike Causer
Bicara tentang orang lain yang terlalu rumit ...
Martin
1
@MikeCauser memimpin nol lebih mudah dibaca dan memberi sinyal maksud kepada pembaca kode nanti. juga lebih baik ketika Anda benar-benar melakukan matematika.
Alexander Mills
11

Coba ini untuk menentukan akurasi:

    time sleep 0.5      # 500 milliseconds (1/2 of a second)
    time sleep 0.001    # 1 millisecond (1/1000 of a second)
    time sleep 1.0      # 1 second (1000 milliseconds)

Kombinasi solusi mr.spuratic dan solusi coles .

dsrdakota
sumber
8

Anda cukup menggunakan usleep. Dibutuhkan mikrodetik (= 1e-6 detik) sebagai parameter, jadi untuk tidur 1 milidetik Anda akan memasukkan:

usleep 1000
Luis Vazquez
sumber
1
$ usleep No command 'usleep' found, did you mean: Command 'sleep' from package 'coreutils' (main) usleep: command not found
Bulletmagnet
Tidak, maksud saya usleepbagian dari initscriptspaket yang standar setidaknya di semua distribusi yang diturunkan Red Hat; termasuk setidaknya RHEL, CentOS, Fedora, Mageia / Mandriva dan SuSE. Berikut sebuah contoh: `` ``
Luis Vazquez
1
Berikut adalah contoh ilustrasi yang berjalan di CentOS 7: `` `$ yang usleep / usr / bin / usleep $ rpm -qf / usr / bin / usleep initscripts-9.49.37-1.el7_3.1.x86_64` `` Untuk meringkas : - sleep(dari coreutils ) bekerja dengan detik - usleep(dari skrip init ) bekerja dengan mikro-detik
Luis Vazquez
4

Saya memiliki masalah yang sama (tidak ada shell yang menggunakan Solaris) jadi saya menulis sendiri:

  #include "stdio.h"
  int main(int argc, char **argv) {
     if(argc == 2) { usleep(atoi(argv[1])); }
     return 0;
}

Tidak memeriksa argumen - Saya akan merekomendasikan yang ditulis dengan benar jika Anda ingin menyimpannya tetapi itu (gcc usleep.c -o usleep) akan membuat Anda keluar dari lubang.

jrichemont
sumber
1
Anda setidaknya dapat mengubah usleep()panggilan kosong if(argc == 1) { usleep(atoi(argv[1])); }untuk menghindari pengindeksan di luar batas array, yang dapat menyebabkan sejumlah perilaku tak terduga.
CVn
@ aCVn Sebenarnya if (argc == 2) { usleep(atoi(argv[1])); }...
Ring Ø
Perhatikan juga bahwa usleepunit adalah μs, jadi untuk menunggu 1 detik, Anda perlu memberikan argumen 1000000.
Dering Ø
@ RingØ Benar. Kesalahan bodoh, tangkapan bagus.
CVn
atoi()adalah pilihan yang mengerikan untuk mengubah string menjadi int. Apa yang atoi( "STRING" )kembali? atoi()tidak memiliki cara untuk mengembalikan kesalahan apa pun.
Andrew Henle