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.