Ich weiß, dass ich warten kann, bis die Bedingung erfüllt ist, indem ich Folgendes tue:
while true; do
test_condition && break
sleep 1
done
Es wird jedoch bei jeder Iteration (Ruhezustand) ein Unterprozess erstellt. Ich könnte sie vermeiden, indem ich tue:
while true; do
test_condition && break
done
Aber es verbraucht viel CPU (beschäftigt warten). Um Unterprozesse und zu lange Wartezeiten zu vermeiden, habe ich die folgende Lösung gefunden, die ich jedoch als hässlich empfinde:
my_tmp_dir=$(mktemp -d --tmpdir=/tmp) # Create a unique tmp dir for the fifo.
mkfifo $my_tmp_dir/fifo # Create an empty fifo for sleep by read.
exec 3<> $my_tmp_dir/fifo # Open the fifo for reading and writing.
while true; do
test_condition && break
read -t 1 -u 3 var # Same as sleep 1, but without sub-process.
done
exec 3<&- # Closing the fifo.
rm $my_tmp_dir/fifo; rmdir $my_tmp_dir # Cleanup, could be done in a trap.
Hinweis: Im Allgemeinen kann ich nicht einfach verwenden read -t 1 var
ohne das FIFO , da es stdin verbraucht und nicht funktioniert, wenn stdin kein Terminal oder keine Pipe ist.
Kann ich auf elegantere Weise Teilprozesse und eifriges Warten vermeiden?
bash
shell-script
sleep
jfg956
quelle
quelle
true
ist ein Builtin und erzeugt in bash keinen Subprozess. Das Warten wird immer schlecht sein.true
, Frage aktualisiert.read -t 1 var
.sleep
wie im ersten Beispiel vorzugehen. Die zweite, auch wenn sie funktioniert, wird in Zukunft für niemanden leicht zu ändern sein. Einfacher Code hat auch ein größeres Potenzial für die Sicherheit.Antworten:
In neueren Versionen von
bash
(mindestens v2) können Builtinsenable -f filename commandname
zur Laufzeit (über ) geladen werden. Eine Reihe solcher ladbarer Buildins wird ebenfalls mit den Bash-Quellen verteilt undsleep
gehört dazu. Die Verfügbarkeit kann natürlich von Betriebssystem zu Betriebssystem (und sogar von Computer zu Computer) unterschiedlich sein. Unter openSUSE werden diese integrierten Funktionen beispielsweise über das Paket verteiltbash-loadables
.Bearbeiten: Paketnamen korrigieren, minimale Bash-Version hinzufügen.
quelle
sleep
als eingebautes installieren . Vielen Dank.In einer inneren Schleife ist es eine schlechte Sache, viele Unterprozesse zu erstellen. Einen erstellen
sleep
Prozesses pro Sekunde ist in Ordnung. Es ist nichts falsch daranWenn Sie den externen Prozess wirklich vermeiden möchten, müssen Sie das FIFO nicht offen halten.
quelle
mkdir
wie es von gemacht wirdmktemp
(wenn nicht, ist es eine Rennbedingung)). Auch stimmt daswhile ! test_condition;
was netter ist als meine Ausgangslösung.Ich hatte vor kurzem das Bedürfnis, dies zu tun. Ich habe mir die folgende Funktion ausgedacht, mit der Bash für immer schlafen kann, ohne ein externes Programm aufzurufen:
ANMERKUNG: Ich habe zuvor eine Version davon gepostet, die den Dateideskriptor jedes Mal öffnete und schloss, aber ich stellte fest, dass sich auf einigen Systemen, die dies hunderte Male pro Sekunde taten, irgendwann einfrieren würde. Somit behält die neue Lösung den Dateideskriptor zwischen den Aufrufen der Funktion bei. Bash räumt es sowieso beim Beenden auf.
Dies kann genau wie / bin / sleep aufgerufen werden und es wird für die angeforderte Zeit schlafen. Ohne Parameter aufgerufen, bleibt es für immer hängen.
In meinem Blog gibt es eine Zusammenfassung mit übermäßigen Details
quelle
read -t 10 < <(:)
sofort zurückkomme, währendread -t 10 <> <(:)
ich die vollen 10 Sekunden warte, aber ich verstehe es immer noch nicht.read -t 10 <> <(:)
welcher nicht<>
stehen?In
ksh93
odermksh
,sleep
ist eine Shell - builtin, also eine Alternative könnte sein , diese Schalen zu verwenden , anstatt vonbash
.zsh
hat auch einzselect
eingebautes (geladen mitzmodload zsh/zselect
), das für eine bestimmte Anzahl von Hundertstelsekunden mit schlafen kannzselect -t <n>
.quelle
Wie Benutzer yoi sagte, wenn in Ihrem Skript stdin geöffnet ist, können Sie anstelle von sleep 1 einfach Folgendes verwenden:
Ab Bash-Version 4.1 können Sie float number verwenden, z
read -t 0.3 ...
Wenn in einem Skript stdin geschlossen ist (Skript wird aufgerufen
my_script.sh < /dev/null &
), müssen Sie einen anderen geöffneten Deskriptor verwenden, der beim Lesen keine Ausgabe erzeugt , z. Standard :Wenn in einem Skript alle Deskriptoren geschlossen sind ( stdin , stdout , stderr ) (z. B. weil es als Daemon bezeichnet wird), müssen Sie eine vorhandene Datei finden, die keine Ausgabe erzeugt:
quelle
read -t 1 3<&- 3<&0 <&3
ist das gleiche wieread -t 0
. Es liest nur von stdin mit Timeout.Dies funktioniert sowohl über eine Login-Shell als auch über eine nicht interaktive Shell.
quelle
read -t 10 <> <(:)
.Brauchst du wirklich einen Fifo? Das Umleiten von stdin zu einem anderen Dateideskriptor sollte ebenfalls funktionieren.
Inspiriert von: Liest die Eingabe in Bash in einer While-Schleife
quelle
Eine leichte Verbesserung gegenüber den oben genannten Lösungen (auf denen ich dies aufgebaut habe).
Reduziert die Notwendigkeit für ein FIFA und damit keine Reinigung zu tun.
quelle
read -t 10 <> <(:)
.