Come posso dormire per un millisecondo in bash o ksh


128

sleep è un comando molto popolare e possiamo iniziare a dormire da 1 secondo:

# wait one second please 
sleep 1

ma quale alternativa se devo aspettare solo 0,1 secondi o tra 0,1 e 1 secondo?

  • Nota: su Linux o OS X sleep 0.XXXfunziona bene, ma su Solaris sleep 0.1o sleep 0.01- Sintassi illegale

2
Posso chiederti perché vuoi dormire per 1ms?
Tom O'Connor,

1
Sì, certo, nel mio script bash aggiungo "sleep 1", in alcune righe, ma lo script viene eseguito molto lentamente, quindi dopo alcune conclusioni ho calcolato che sleep 0.1 porta anche buoni risultati e più veloce sul ritardo, ho bisogno di un ritardo nell'ordine per risolvere il problema ssh nel mio script bash, eseguo il login di paralel ssh su alcune macchine aspettandomi e senza indugio non funzionerà, come sai dalla mia domanda il ritardo dovrebbe adattarsi sia a Linux che a Solaris
yael

3
Qualunque sia la soluzione scelta, tieni presente che uno script di shell non sarà molto preciso in termini di tempistica.
scai,

Che ne dici di fare qualcosa che richiede pochissimo tempo per essere eseguito, ma non fa nulla .. tipoecho "" >/dev/null
Tom O'Connor,

Buona idea ma come prende questo comando msec? , Ho bisogno di 0,1 msec, non meno di questo - :)
yael

Risposte:


68

Bash ha una sospensione "caricabile" che supporta i secondi frazionari ed elimina le spese generali di un comando esterno:

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

Poi:

$ 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

Lo svantaggio è che i file caricabili potrebbero non essere forniti con il file bashbinario, quindi è necessario compilarli come mostrato (anche se su Solaris non sarebbe necessariamente semplice come sopra).

A partire dabash-4.4 (settembre 2016) tutti i caricabili sono ora costruiti e installati per impostazione predefinita su piattaforme che lo supportano, sebbene siano costruiti come file di oggetti condivisi separati e senza .sosuffisso. A meno che la tua distribuzione / OS non abbia fatto qualcosa di creativo, dovresti invece essere in grado di fare:

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

(La pagina man implica che BASH_LOADABLES_PATHè impostata automaticamente, trovo che questo non sia il caso nella distribuzione ufficiale a partire dal 4.4.12. Se e quando è impostato correttamente, è necessario solo enable -f filename commandnamecome richiesto.)

Se ciò non è adatto, la prossima cosa più semplice da fare è costruire o ottenere sleepdai coreutils GNU, questo supporta la funzionalità richiesta. Il sleepcomando POSIX è minimo, le versioni precedenti di Solaris hanno implementato solo questo. Solaris 11 sleep fa sostenere frazioni di secondo.

Come ultima risorsa potresti usare perl(o qualsiasi altro script che devi tenere a portata di mano) con l'avvertenza che l'inizializzazione dell'interprete potrebbe essere paragonabile al tempo di sonno previsto:

$ perl -e "select(undef,undef,undef,0.1);"
$ echo "after 100" | tclsh

2
Ah, dato che stai usando expect, probabilmente puoi semplicemente usare " after N", dove N è millisecondi, direttamente nel tuo script.
signor spuratic

usa usleepcome @Luis Vazquez e @sebix write
Ilan.K

Apple MacOS ha la
sospensione

125

La documentazione per il sleepcomando da coreutils dice:

Le implementazioni storiche di sleep hanno richiesto che quel numero fosse un numero intero e accettavano solo un singolo argomento senza suffisso. Tuttavia, la sospensione GNU accetta numeri in virgola mobile arbitrari. Vedi virgola mobile .

Quindi è possibile utilizzare sleep 0.1, sleep 1.0e-1e gli argomenti analoghi.


1
vedere la mia osservazione sul sistema operativo SOLARIS
yael

Hai confuso è e non è ?
scai,

vedi il mio aggiornamento nella mia domanda
yael

1
Yael, penso che ci siano ancora troppi aspetti negativi nella tua domanda; sei sicuro di voler dire "sintassi non illegale"?
MadHatter,

per esempio - Corro su Solaris 10: # sleep 0.1 sleep: cattivo carattere nell'argomento, su Linux sleep 0.1 funziona bene
yael

58

Sleep accetta numeri decimali in modo da poterlo scomporre in questo modo:

1/2 di secondo

 sleep 0.5

1/100 di secondo

sleep 0.01

Quindi per un millisecondo vorresti

sleep 0.001

4
È inoltre possibile eliminare lo zero iniziale prima del punto decimale. per esempio. sleep .5
Mike Causer,


Parla di tutti gli altri che lo complicano troppo ...
Martin,

1
Gli zeri iniziali di @MikeCauser sono molto più leggibili e indicano in seguito al lettore il codice. anche meglio quando effettivamente fai matematica.
Alexander Mills,


8

Puoi semplicemente usare usleep. Ci vogliono microsecondi (= 1e-6 secondi) come parametro, quindi per dormire 1 millisecondo inserire:

usleep 1000

1
$ usleep No command 'usleep' found, did you mean: Command 'sleep' from package 'coreutils' (main) usleep: command not found
Bulletmagnet,

No, intendo usleepparte del initscriptspacchetto che è standard almeno in tutte le distribuzioni derivate da Red Hat; tra cui almeno RHEL, CentOS, Fedora, Mageia / Mandriva e SuSE. Ecco un esempio: ``
Luis Vazquez,

1
Ecco un esempio di illustrazione in esecuzione in CentOS 7: `` $ che usleep / usr / bin / usleep $ rpm -qf / usr / bin / usleep initscripts-9.49.37-1.el7_3.1.x86_64 `` `Per riassumere : - sleep(da coreutils ) funziona con i secondi - usleep(da initscripts ) funziona con i micro-secondi
Luis Vazquez,

4

Ho avuto lo stesso problema (nessuna shell usleep su Solaris) quindi ho scritto il mio così:

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

Non controlla gli argomenti - ti consiglio di scriverne uno correttamente se vuoi tenerlo, ma che (gcc usleep.c -o usleep) ti farà uscire da un buco.


1
Potresti almeno modificare quella usleep()chiamata nuda if(argc == 1) { usleep(atoi(argv[1])); }per evitare l'indicizzazione al di fuori dei limiti dell'array, il che può portare a un numero qualsiasi di comportamenti imprevisti.
un CVn

@aCVn In realtà è if (argc == 2) { usleep(atoi(argv[1])); }...
Anello Ø

Si noti inoltre che l' usleepunità è μs, quindi per attendere 1 secondo, è necessario fornire un argomento 1000000.
Anello Ø

@ RingØ Right. Stupido errore, buona cattura.
un CVn il

atoi()è una scelta orribile per convertire una stringa in un int. Cosa atoi( "STRING" )ritorna? atoi()non ha modo di restituire alcun errore.
Andrew Henle,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.