Je sais que je peux attendre une condition pour devenir vrai en bash en faisant:
while true; do
test_condition && break
sleep 1
done
Mais il crée 1 sous-processus à chaque itération (sommeil). Je pourrais les éviter en faisant:
while true; do
test_condition && break
done
Mais il utilise beaucoup de CPU (attente occupée). Pour éviter les sous-processus et les attentes occupées, j'ai trouvé la solution ci-dessous, mais je la trouve moche:
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.
Remarque: dans le cas général, je ne peux pas simplement utiliser read -t 1 var
sans le fifo, car il consommera stdin et ne fonctionnera pas si stdin n'est pas un terminal ou un pipe.
Puis-je éviter les sous-processus et les attentes occupées de manière plus élégante?
bash
shell-script
sleep
jfg956
la source
la source
true
est une fonction intégrée et ne crée pas de sous-processus dans bash. une attente occupée sera toujours mauvaise.true
, question mise à jour.read -t 1 var
.sleep
comme dans le premier exemple. Le second, même s'il peut fonctionner, ne sera pas facile pour quiconque de s'adapter à l'avenir. Le code simple a également un plus grand potentiel de sécurité.Réponses:
Dans les versions plus récentes de
bash
(au moins v2), les commandes internes peuvent être chargées (viaenable -f filename commandname
) au moment de l'exécution. Un certain nombre de ces prédéfinis chargeables est également distribué avec les sources bash, et ensleep
fait partie. La disponibilité peut différer d'un OS à l'autre (et même d'une machine à l'autre), bien sûr. Par exemple, sur openSUSE, ces commandes internes sont distribuées via le packagebash-loadables
.Edit: correction du nom du package, ajout d'une version bash minimale.
la source
sleep
tant que intégré. Merci.La création d'un grand nombre de sous-processus est une mauvaise chose dans une boucle interne. Créer un
sleep
processus par seconde est OK. Il n'y a rien de mal àSi vous voulez vraiment éviter le processus externe, vous n'avez pas besoin de garder le fifo ouvert.
la source
mkdir
comme c'est fait parmktemp
(sinon, c'est une condition de course)). C'est également vrai pour cewhile ! test_condition;
qui est plus agréable que ma solution initiale.J'ai récemment eu besoin de faire ça. J'ai proposé la fonction suivante qui permettra à bash de dormir indéfiniment sans appeler de programme externe:
REMARQUE: j'ai déjà publié une version de ceci qui ouvrirait et fermerait le descripteur de fichier à chaque fois, mais j'ai constaté que sur certains systèmes, le faire des centaines de fois par seconde finirait par se bloquer. Ainsi, la nouvelle solution conserve le descripteur de fichier entre les appels à la fonction. Bash le nettoiera quand même à la sortie.
Cela peut être appelé comme / bin / sleep, et il dormira pendant la durée demandée. Appelé sans paramètres, il se bloque pour toujours.
Il y a un article avec des détails excessifs sur mon blog ici
la source
read -t 10 < <(:)
revient immédiatement enread -t 10 <> <(:)
attendant les 10 secondes, mais je ne comprends toujours pas.read -t 10 <> <(:)
quoi ça veut dire<>
?Dans
ksh93
ormksh
,sleep
est un shell intégré, donc une alternative pourrait être d'utiliser ces shells à la place debash
.zsh
a également unzselect
intégré (chargé aveczmodload zsh/zselect
) qui peut dormir pendant un nombre donné de centièmes de secondes aveczselect -t <n>
.la source
Comme l' a dit l' utilisateur yoi , si dans votre script est ouvert stdin , alors au lieu de dormir 1, vous pouvez simplement utiliser:
Dans Bash version 4.1 et plus récente, vous pouvez utiliser un nombre flottant, par exemple
read -t 0.3 ...
Si dans un script stdin est fermé (le script est appelé
my_script.sh < /dev/null &
), alors vous devez utiliser un autre descripteur ouvert, qui ne produit pas de sortie lorsque la lecture est exécutée, par exemple. stdout :Si dans un script tous les descripteurs sont fermés ( stdin , stdout , stderr ) (par exemple parce qu'il est appelé comme démon), alors vous devez trouver tout fichier existant qui ne produit pas de sortie:
la source
read -t 1 3<&- 3<&0 <&3
est le même queread -t 0
. C'est juste la lecture de stdin avec timeout.Cela fonctionne à partir d'un shell de connexion ainsi que d'un shell non interactif.
la source
read -t 10 <> <(:)
.Avez-vous vraiment besoin d'un fifo? La redirection de stdin vers un autre descripteur de fichier devrait également fonctionner.
Inspiré par: Lire l'entrée dans bash à l'intérieur d'une boucle while
la source
Une légère amélioration par rapport aux solutions mentionnées ci-dessus (sur lesquelles je me suis basé).
Réduit le besoin d'un fifo et donc pas de nettoyage à faire.
la source
read -t 10 <> <(:)
.