Wie schlafe ich für eine Millisekunde in bash oder ksh

128

sleep ist ein sehr beliebter Befehl und wir können den Schlaf ab 1 Sekunde starten:

# wait one second please 
sleep 1

aber was ist die Alternative, wenn ich nur 0,1 Sekunden oder zwischen 0,1 bis 1 Sekunde warten muss?

  • Bemerkung: unter Linux oder OS X sleep 0.XXXfunktioniert es gut, aber unter Solaris sleep 0.1oder sleep 0.01- illegaler Syntax
yael
quelle
2
Kann ich fragen, warum Sie 1ms schlafen wollen?
Tom O'Connor
1
Ja, natürlich, in meinem Bash-Skript füge ich in einigen Zeilen "sleep 1" hinzu, aber das Skript läuft sehr langsam, so dass ich nach einiger Schlussfolgerung berechne, dass sleep 0.1 auch gute Ergebnisse bringt und schneller Über die Verzögerung muss ich mich in Ordnung bringen ssh Problem in meinem bash - Skript zu lösen, führe ich an einigen Maschinen paralel sSH - Login durch erwarten und unverzüglich seine nicht funktioniert, wie Sie aus der Liste meiner Frage wissen , sollte die Verzögerung Linux und Solaris passen
Yael
3
Denken Sie bei jeder Lösung daran, dass ein Shell-Skript hinsichtlich des Timings nicht sehr genau ist.
Scai
Wie wäre es, wenn Sie etwas tun, dessen Ausführung nur sehr kurze Zeit in echo "" >/dev/null
Tom O'Connor
Gute Idee, aber wie lange dauert dieser Befehl? Ich brauche 0,1 ms, nicht weniger als das - :)
Yael

Antworten:

68

Bash verfügt über einen "ladbaren" Ruhezustand, der Sekundenbruchteile unterstützt und den Overhead eines externen Befehls eliminiert:

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

Dann:

$ 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

Der Nachteil ist, dass die Loadables möglicherweise nicht mit Ihrer bashBinärdatei geliefert werden. Sie müssten sie daher wie gezeigt selbst kompilieren (unter Solaris ist dies jedoch nicht unbedingt so einfach wie oben beschrieben).

Abbash-4.4 (September 2016) werden alle Loadables standardmäßig auf Plattformen erstellt und installiert, die dies unterstützen. Sie werden jedoch als separate Shared Object-Dateien ohne .soSuffix erstellt. Sofern Ihre Distribution / Ihr Betriebssystem nichts Kreatives geleistet hat, sollten Sie stattdessen Folgendes tun können:

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

(Die Manpage impliziert BASH_LOADABLES_PATH, dass sie automatisch gesetzt wird. Ich finde, dass dies in der offiziellen Distribution ab 4.4.12 nicht der Fall ist. Wenn und wann sie richtig gesetzt ist, brauchen Sie nur enable -f filename commandnamedie erforderlichen Einstellungen .)

Wenn dies nicht geeignet ist, ist es am einfachsten, sleepGNU-Coreutils zu erstellen oder von diesen zu beziehen. Dies unterstützt die erforderliche Funktion. Der POSIX- sleepBefehl ist minimal, ältere Solaris-Versionen haben nur diesen implementiert. Solaris 11 sleep tut Sekundenbruchteile unterstützen.

Als letzten Ausweg können Sie perl(oder jedes andere Skript, das Sie zur Hand haben) mit der Einschränkung verwenden, dass das Initialisieren des Interpreters möglicherweise mit der beabsichtigten Ruhezeit vergleichbar ist:

$ perl -e "select(undef,undef,undef,0.1);"
$ echo "after 100" | tclsh
mr.spuratic
quelle
2
Ah, da Sie verwenden expect, können Sie wahrscheinlich einfach " after N", wobei N Millisekunden ist, direkt in Ihrem Skript verwenden.
mr.spuratic
Verwenden Sie usleepwie @ Luis Vazquez und @ Sebix schreiben
Ilan.K
Apple MacOS hat BSD-Schlaf, der auch Sekundenbruchteile unterstützt
Roblogic
125

In der Dokumentation zum sleepBefehl von coreutils heißt es:

Historische Implementierungen von sleep haben vorausgesetzt, dass number eine Ganzzahl ist und nur ein einziges Argument ohne Suffix akzeptiert. GNU sleep akzeptiert jedoch beliebige Gleitkommazahlen. Siehe Gleitkomma .

Somit können Sie verwenden sleep 0.1, sleep 1.0e-1und ähnliche Argumente.

scai
quelle
1
siehe meine Bemerkung zu SOLARIS OS
yael
Hast du verwechselt ist und ist nicht ?
Scai
siehe mein update in meiner frage
yael
1
Yael, ich glaube, deine Frage enthält immer noch zu viele Negative. Sind Sie sicher, dass Sie "nicht illegale Syntax" meinen?
MadHatter
zum beispiel - ich laufe auf solaris 10 so: # sleep 0.1 sleep: schlechtes
zeichen
58

Sleep akzeptiert Dezimalzahlen, so dass Sie diese wie folgt aufteilen können:

1/2 Sekunde

 sleep 0.5

1/100 Sekunde

sleep 0.01

Also für eine Millisekunde würden Sie wollen

sleep 0.001
colealtdelete
quelle
4
Sie können die führende Null auch vor dem Dezimalpunkt ablegen. z.B. sleep .5
Mike Causer
Sprechen Sie über alle anderen, die es zu kompliziert machen ...
Martin
1
@MikeCauser führende Nullen sind viel besser lesbar und signalisieren dem Leser später die Absicht des Codes. auch besser, wenn du tatsächlich Mathe machst.
Alexander Mills
11

Versuchen Sie dies, um die Genauigkeit zu bestimmen:

    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)

Kombination der Lösung von mr.spuratic und der Lösung von coles .

dsrdakota
quelle
8

Sie können einfach verwenden usleep. Es dauert Mikrosekunden (= 1e-6 Sekunden) als Parameter, sodass Sie für den Ruhezustand 1 Millisekunde eingeben würden:

usleep 1000
Luis Vazquez
quelle
1
$ usleep No command 'usleep' found, did you mean: Command 'sleep' from package 'coreutils' (main) usleep: command not found
Bulletmagnet
Nein, ich meine einen usleepTeil des initscriptsPakets, der zumindest in allen von Red Hat abgeleiteten Distributionen Standard ist. einschließlich mindestens RHEL, CentOS, Fedora, Mageia / Mandriva und SuSE. Hier ein Beispiel: `` `
Luis Vazquez
1
Hier ist eine Beispielillustration, die unter CentOS 7 ausgeführt wird: `` `$, die / usr / bin / usleep $ rpm -qf / usr / bin / usleep initscripts-9.49.37-1.el7_3.1.x86_64` `` um es zusammenzufassen : - sleep(von coreutils ) arbeitet mit Sekunden - usleep(von initscripts ) arbeitet mit Mikrosekunden
Luis Vazquez
4

Ich hatte das gleiche Problem (kein Shell-Usleep unter Solaris), also schrieb ich mein eigenes so:

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

Überprüft keine Argumente - ich empfehle ein richtig geschriebenes, wenn Sie es behalten möchten, aber das (gcc usleep.c -o usleep) wird Sie aus einem Loch herausholen.

jrichemont
quelle
1
Sie können diesen Aufruf zumindest so ändern, dass eine Indizierung außerhalb der Array-Grenzen vermieden wird, was zu einer beliebigen Anzahl unerwarteter Verhaltensweisen führen kann. usleep()if(argc == 1) { usleep(atoi(argv[1])); }
ein Lebenslauf vom
@aCVn Es ist tatsächlich if (argc == 2) { usleep(atoi(argv[1])); }...
Ring-Ø
Beachten Sie auch, dass die usleepEinheit μs ist. Wenn Sie also 1 Sekunde warten möchten, müssen Sie ein 1000000-Argument eingeben.
Ring
@ RingØ Richtig. Blöder Fehler, guter Fang.
ein Lebenslauf
atoi()ist eine schreckliche Wahl, um eine Zeichenfolge in eine umzuwandeln int. Was kehrt atoi( "STRING" )zurück? atoi()kann keinen Fehler zurückgeben.
Andrew Henle