Shell: Ist es möglich, einen Befehl zu verzögern, ohne `sleep` zu verwenden?


21

Gibt es Ersatz, Alternativen oder Bash-Tricks, um Befehle zu verzögern, ohne sie zu verwenden sleep? Führen Sie beispielsweise den folgenden Befehl aus, ohne den Energiesparmodus tatsächlich zu verwenden:

$ sleep 10 && echo "This is a test"

42
Was ist los mit sleep?
Muru

5
Es gibt keinen anderen Grund als Neugier. Ich dachte, es wäre interessant, alternative Lösungen zu lernen. Ich denke, es atkönnte eines sein, aber ich konnte keine Verwendungsbeispiele finden.
User321697

1
@ user321697 "at" dient zum Planen einzelner Jobs. Sie werden vom atd-Dienst ausgeführt, sodass Ihr Shell-Skript nicht angehalten wird. Ein Anwendungsfall für at wäre, es zu einem bestimmten Zeitpunkt (asynchron) ausführen zu lassen und eine Markierungsdatei zu erstellen, wenn sie fertig ist, während Ihr Skript darauf wartet, dass diese Datei in einer while-Schleife angezeigt wird. Sie können einen ähnlichen Effekt erzielen, indem Sie einen Job so planen, dass er Ihrem Skript ein SIGCONT sendet, und dann Ihr Skript einfrieren, indem Sie sich ein SIGSTOP senden.
Grega Bremec

1
Ich bin hierher gekommen und habe erwartet, dass jeder einen Spinlock vorschlägt. Ich bin angenehm überrascht von all den Antworten.
Daan van Hoek

3
Re: „Curiosity“ - in unix.stackexchange.com/help/dont-ask , beachten Sie die Anforderung , dass „Sie nur praktisch, beantwortbar Fragen stellen sollte , basierend auf tatsächlichen Probleme , die Sie Gesicht. - dass dies war gut Trotz Kontroverse erhalten, macht diese Richtlinie eine eher seltene Ausnahme.
Charles Duffy

Antworten:


17

Sie haben Alternativen zu sleep: Sie sind atund cron. Im Gegensatz dazu sleepmüssen Sie den Zeitpunkt angeben, zu dem sie ausgeführt werden sollen.

  • Stellen Sie sicher, dass der atdDienst ausgeführt wird, indem Sie ausführen service atd status.
    Angenommen, das Datum ist 11:17 Uhr UTC. Wenn Sie einen Befehl , um 11:25 UTC ausführen müssen, ist die Syntax: echo "This is a test" | at 11:25.
    Denken Sie jetzt daran, dass atdstandardmäßig nicht die Fertigstellung der Jobs protokolliert wird. Weitere Informationen finden Sie unter diesem Link . Es ist besser, wenn Ihre Anwendung über eine eigene Protokollierung verfügt.

  • Sie können Jobs in planen. cronWeitere Informationen finden Sie unter: man cronAnzeigen der Optionen oder crontab -eHinzufügen neuer Jobs. /var/log/cronkann auf Informationen zur Ausführung von Jobs überprüft werden.

Zu sleep system call Ihrer Information: Die aktuelle Ausführung wird angehalten und für das übergebene Argument geplant.

BEARBEITEN:

Wie @Gaius bereits erwähnt hat, können Sie dem Befehl auch Minuten hinzufügen. Aber atsagen wir mal, die Zeit ist 12:30:30und jetzt haben Sie den Scheduler mit ausgeführt now +1 minutes. Obwohl 1 Minute angegeben wurde, was 60 Sekunden atentspricht, wartet das Programm nicht wirklich, bis 12:31:30der Job ausgeführt wird, sondern führt den Job unter aus 12:31:00. Die Zeiteinheiten können sein minutes, hours, days, or weeks. Weitere Informationen finden Sie unterman at

z.B: echo "ls" | at now +1 minutes


7
Dies ist nicht wahr, Sie können einen at-Job für beispielsweise jetzt +1 Minute einplanen, um in einer Minutenzeit zu laufen
Gaius,

29

Mit bashBuiltins können Sie Folgendes tun:

coproc read -t 10 && wait "$!" || true

10 Sekunden schlafen ohne zu benutzen sleep. Das coprocist so zu machen, dass reads stdin eine Pfeife ist, aus der nie etwas rauskommt. Dies || trueliegt daran wait, dass der Beendigungsstatus eine SIGALRM-Übermittlung widerspiegelt, die dazu führen würde, dass die Shell beendet wird, wenn die errexitOption festgelegt ist.

In anderen Schalen:

mkshund eingebaut ksh93haben sleep, keinen Sinn, etwas anderes zu verwenden (obwohl sie beide auch unterstützen read -t).

zshunterstützt auch read -t, hat aber auch einen eingebauten Wrapper select(), so dass Sie auch verwenden können:

zmodload zsh/zselect
zselect -t 1000 # centiseconds

Wenn Sie die Ausführung von einer interaktiven Shell-Sitzung aus planen möchten, lesen Sie auch das zsh/schedModul inzsh .


Würden Sie darüber nachdenken read -t 10 < /dev/zero || true?
Jeff Schaller

5
@ JeffSchaller Ich würde es vermeiden, da das eine belegte Schleife ist.
Stéphane Chazelas

@ StéphaneChazelas Ich würde nicht erwarten, dass es sich um eine Busy-Loop handelt. Ich würde erwarten, dass alle Shells readmit select (2) oder ähnlichem implementiert werden (dies impliziert, dass Read-with-Timeout eine gute Antwort auf diese Frage wäre). Ich drücke eher Überraschung als Widerspruch zu Ihnen aus, aber können Sie auf eine weitere Diskussion darüber hinweisen?
Norman Gray

5
@NormanGray /dev/zeroist eine Datei, die unendlich viele Daten (NUL-Bytes) enthält. So readwird so viel wie möglich in diesen 10 Sekunden gelesen. Zum Glück wird in dem Fall, in dem bashdas Speichern von NUL-Bytes in seinen Variablen nicht unterstützt wird, kein Speicher verbraucht, aber die CPU-Ressourcen werden trotzdem beansprucht.
Stéphane Chazelas

1
Wenn @NormanGray von einem Terminal aus ausgeführt wird, handelt /dev/stdoutes sich um das tty-Gerät. Dies hätte also Nebenwirkungen (wie das Stoppen des Skripts, wenn es im Hintergrund ausgeführt wird) und würde zurückgegeben, wenn der Benutzer beispielsweise die Eingabetaste drückt. read -t 10 /dev/stdout | :würde unter Linux funktionieren, aber nur unter Linux, während coprocunabhängig vom Betriebssystem funktionieren sollte.
Stéphane Chazelas

7

Einige andere Ideen.

top -d10 -n2 >/dev/null

vmstat 10 2 >/dev/null

sar 10 1 >/dev/null

timeout 10s tail -f /dev/null

1
Du hast meine Vorstellung von Zeitlimit / Timeout "gestohlen" ... +1
Rui F Ribeiro

1
Ohhhh mein Gott, danke, ich war in einer Situation ohne Schlaf, top ist der Wahnsinn!
Fire-Dragon-DoL

6

Da es Antworten gibt, die vorschlagen, die nicht standardmäßige -t delayOption von zu verwenden read, haben Sie hier die Möglichkeit, in einer Standard-Shell ein Zeitlimit für das Lesen festzulegen:

{ ss=`stty -g`; stty -icanon min 0 time 20; read foo; stty "$ss"; }

Das Argument für stty timeist in Zehntelsekunden.


5

Verwenden der integrierten Variablen bash $SECONDSund einer Besetzt-Schleife:

for((target=$((SECONDS + 10)); SECONDS < target; true)); do :; done

2
Das wäre in der Tat Pause für eine Dauer im Bereich irgendwo zwischen 9 und 10 Sekunden aber (aufgrund eines Fehlers inbash , zshund mkshhatte ähnliche Probleme , aber seit behoben)
Stéphane Chazelas

7
Ein guter Weg, um Wärme zu machen.
Strg-Alt-Delor

6
Ich werde nicht das erste Mal beschuldigt, voller heißer Luft zu sein! :)
Jeff Schaller

4

Der älteste Trick im Buch:

read && echo "This is a test"

Einfach drücken Enterund es geht weiter!


Dies ist nicht der Fall, wenn der Prozess interaktionsfrei oder im Hintergrund ausgeführt werden muss, oder?
ss_iwe

Richtig: Aber das war nicht die Anforderung des OP gemäß der ursprünglichen Frage, also immer noch eine gültige Antwort ... ;
Fabby,

1
OP gibt speziell ein Beispiel (mit sleep) und fragt nach einer gleichwertigen Alternative ohne. Also readnicht analysieren, sorry. ;)
AnoE

@AnoE Stéphanes Antwort ist natürlich die beste, meine ist nur die älteste --- press «enter» to continue --- ;-)
Fabby

4

In den Tagen von Mikrocomputern, auf denen BASIC ausgeführt wurde, wurden Verzögerungen normalerweise mit einer leeren Schleife ausgeführt:

FOR I = 1 TO 10000:NEXT

Das gleiche Prinzip könnte verwendet werden, um eine Verzögerung in ein Shell-Skript einzufügen:

COUNTER=0; while [ $COUNTER -lt 10000 ]; do :; let COUNTER=COUNTER+1; done

Das Problem bei diesem Ansatz ist natürlich, dass die Länge der Verzögerung von Maschine zu Maschine entsprechend ihrer Prozessorgeschwindigkeit (oder sogar auf derselben Maschine unter verschiedenen Lasten) variiert. Im Gegensatz dazu sleepwird es wahrscheinlich auch Ihre CPU (oder einen seiner Kerne) ausschöpfen.


2
Ein guter Weg, um Wärme zu machen.
Strg-Alt-Delor

2
Verzögerungsschleifen sind eine schreckliche Idee für alles andere als den kürzesten Ruhezustand (ein paar Nanosekunden oder Taktzyklen in einem Gerätetreiber) auf jeder modernen CPU, auf der ein Unix-ähnliches Betriebssystem ausgeführt werden kann. Das heißt, ein so kurzer Ruhezustand, dass die CPU während des Wartens keine weiteren Aktionen ausführen kann, z. B. einen anderen Prozess einplanen oder in einen Energiesparmodus wechseln kann, bevor sie bei einem Timer-Interrupt aufwacht. Die dynamische CPU-Frequenz macht es unmöglich, eine Verzögerungsschleife für Zählimpulse pro Sekunde zu kalibrieren, außer als Mindestverzögerung, die bei niedrigen Taktraten möglicherweise viel länger schläft, bevor sie hochgefahren wird.
Peter Cordes

Alte Computer hatten einen Stromverbrauch, der viel weniger von der Arbeitslast abhängig war. Moderne CPUs müssen verschiedene Teile des Chips so weit wie möglich dynamisch ausschalten, um nicht zu schmelzen (z. B. Teile der FPU- oder SIMD-Ausführungseinheiten ausschalten, während nur ganzzahliger Code ausgeführt wird, oder zumindest das Taktsignal auf Teile des Chips leiten das muss kein Wechsel sein). Der Energiesparmodus im Leerlauf (anstatt in einer Endlosschleife auf Timer-Interrupts zu warten) ist ebenfalls aktueller als die von Ihnen erwähnten alten Computer.
Peter Cordes

Weitere Informationen zur CPU-Historie finden Sie in Modern Microprocessors A 90-Minute Guide! - lighterra.com/papers/modernmicroprocessors .
Peter Cordes

3

Es gibt kein eingebautes Gerät, das dasselbe macht wie sleep(es sleepsei denn, es ist eingebaut). Es gibt jedoch einige andere Befehle, die warten.

Einige davon sind.

  • atund cron: Dient zum Planen von Aufgaben zu einem bestimmten Zeitpunkt.

  • inotifywait: Dient zum Warten auf eine Datei oder zum Ändern / Entfernen / Hinzufügen / etc


Danke dafür. Können Sie ein Beispiel für die Ausführung einer geplanten Aufgabe (in 10 Sekunden) mit atangeben?
User321697

1
ein edit und ein upvote! ;-)
Fabby

cronAufgaben speichern in crontab, oder? Wo werden atdie geplanten Daten gespeichert?
User321697

@ user321697 Bereits hier
Fabby

Es tut mir leid, dass Sie Ihre Bearbeitung auf das F zurückgesetzt haben: Sie haben den Hauptzweck der OPs-Frage geändert, wodurch die einfachste Antwort von allen ungültig würde ... ¯ \ _ (ツ) _ / ¯
Fabby

3

Ein Klassiker aus dem Land der Fenster und Batches:

ping -c 11 localhost >/dev/null && echo "This is a test"

Eine falsche Konfiguration der Firewall oder des Namenssystems kann zu einer erheblichen zusätzlichen Verzögerung führen.
Spektren

1
127.0.0.1 ... @spectras
AnoE

1
Zum Glück wird es nicht mehr benötigt, da Windows jetzt den systemeigenen Energiesparmodus unterstützt.
Baldrickk

1
@AnoE> löst den Namenssystemteil, nicht den Firewallteil. Obwohl dies nicht üblich ist, kann es so konfiguriert werden, dass Pings im Hintergrund auf der lokalen Schnittstelle gelöscht werden. Das führt dazu, dass Ping viel länger wartet.
Spektren

+1 für die "schönen" Erinnerungen
AC

0

Wenn Sie interaktiv auf eine neue Zeile in einer Datei warten möchten, dann

tail -f
.

Warten auf eine Änderung in einem Dateisystem? Dann benutze zB

inotify / inoticoming
.

Und es gibt andere Möglichkeiten, je nachdem, was Sie mit "warten" meinen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.