Shell: est-il possible de retarder une commande sans utiliser `sleep`?


21

Existe-t-il des substituts, des alternatives ou des astuces bash pour retarder les commandes sans utiliser sleep? Par exemple, exécuter la commande ci-dessous sans utiliser réellement sleep:

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

42
Qu'est-ce qui ne va pas sleep?
muru

5
Il n'y a pas de vraie raison autre que la curiosité. J'ai pensé qu'il serait intéressant d'apprendre quelques solutions alternatives. Je pense que atpeut-être un, mais je n'ai trouvé aucun exemple d'utilisation.
user321697

1
@ user321697 «at» sert à planifier des travaux uniques. ils sont exécutés par le service atd, donc ils ne mettront pas en pause votre script shell. un cas d'utilisation pour at serait de lui faire faire quelque chose à un moment spécifié (async) et de créer un fichier marqueur quand il est terminé, pendant que votre script attend que ce fichier apparaisse dans une boucle while. vous pouvez obtenir un effet similaire en planifiant un travail pour envoyer votre script un SIGCONT puis en gelant votre script en vous envoyant un SIGSTOP.
Grega Bremec

1
Je suis venu ici en m'attendant à ce que tout le monde suggère un spinlock. Je suis agréablement surpris par toutes les réponses.
Daan van Hoek

3
Re: "Curiosity" - dans unix.stackexchange.com/help/dont-ask , notez l'exigence selon laquelle "vous ne devez poser des questions pratiques et responsables que sur la base des problèmes réels que vous rencontrez. " - que cela a été bien- reçu malgré la controverse selon laquelle cette directive en fait une exception assez rare.
Charles Duffy

Réponses:


17

Vous avez des alternatives à sleep: Ils sont atet cron. Contrairement à sleepceux-ci, vous devez fournir l'heure à laquelle vous en avez besoin pour fonctionner.

  • Assurez-vous que le atdservice fonctionne en exécutant service atd status.
    Supposons maintenant que la date soit 11 h 17 UTC; si vous avez besoin d'exécuter une commande à 11h25 UTC, la syntaxe est: echo "This is a test" | at 11:25.
    Gardez maintenant à l'esprit que, atdpar défaut, ne consignera pas la fin des travaux. Pour en savoir plus, consultez ce lien . Il vaut mieux que votre application dispose de sa propre journalisation.

  • Vous pouvez planifier des travaux dans cron, pour plus d'informations: man cronpour voir ses options ou crontab -epour ajouter de nouveaux travaux. /var/log/cronpeut être vérifié pour les informations sur l'exécution des travaux.

FYI sleep system call suspend l'exécution en cours et la planifie par rapport à l'argument qui lui a été transmis.

MODIFIER:

Comme @Gaius l'a mentionné, vous pouvez également ajouter des minutes à la commande, mais atdisons que l'heure est 12:30:30et maintenant vous avez exécuté le planificateur avec now +1 minutes. Même si 1 minute, ce qui correspond à 60 secondes, a été spécifié, le atn'attend pas vraiment 12:31:30pour exécuter le travail, il exécute plutôt le travail à 12:31:00. Les unités de temps peuvent être minutes, hours, days, or weeks. Pour plus de référenceman at

par exemple: echo "ls" | at now +1 minutes


7
Ce n'est pas vrai, vous pouvez planifier un travail au pour dire maintenant +1 minute, pour exécuter dans un temps de minutes
Gaius

29

Avec les bashbuiltins, vous pouvez faire:

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

Dormir 10 secondes sans utiliser sleep. Il coprocs'agit de faire en sorte que readstdin soit une pipe d'où rien ne sortira jamais. || trueest parce que waitle statut de sortie de 'reflétera une livraison SIGALRM qui entraînerait la fermeture du shell si l' errexitoption est définie.

Dans d'autres coquilles:

mkshet ksh93ont sleepintégré, inutile d'utiliser autre chose là-bas (bien qu'ils prennent également en charge tous les deux read -t).

zshprend également en charge read -t, mais dispose également d'un wrapper intégré select(), vous pouvez donc également utiliser:

zmodload zsh/zselect
zselect -t 1000 # centiseconds

Si vous voulez planifier l'exécution de choses à partir d'une session shell interactive, consultez également le zsh/schedmodule danszsh .


Envisageriez-vous read -t 10 < /dev/zero || true?
Jeff Schaller

5
@JeffSchaller Je l'éviterais car c'est une boucle occupée.
Stéphane Chazelas

@ StéphaneChazelas Je ne m'attendrais pas à ce que ce soit une boucle occupée - je m'attendrais à ce que n'importe quel shell readsoit implémenté en utilisant select (2) ou quelque chose de similaire (impliquant que la lecture avec délai d'attente serait une bonne réponse à cette question). J'exprime la surprise plutôt que de vous contredire, mais pouvez-vous indiquer une discussion plus approfondie à ce sujet?
Norman Gray

5
@NormanGray, /dev/zeroest un fichier qui contient une quantité infinie de données (octets NUL). Alors readlira autant que possible pendant ces 10 secondes. Heureusement, dans le cas bashoù ne prend pas en charge le stockage d'octets NUL dans ses variables, cela n'utilisera pas de mémoire, mais cela consommera toujours des ressources CPU.
Stéphane Chazelas

1
@NormanGray, s'il était exécuté à partir d'un terminal, /dev/stdoutserait le périphérique tty, il aurait donc des effets secondaires (comme arrêter le script s'il était exécuté en arrière-plan) et reviendrait si l'utilisateur appuie sur Entrée, par exemple. read -t 10 /dev/stdout | :fonctionnerait sur Linux, mais sur Linux uniquement, alors qu'il coprocdevrait fonctionner quel que soit le système d'exploitation.
Stéphane Chazelas

7

Quelques autres idées.

top -d10 -n2 >/dev/null

vmstat 10 2 >/dev/null

sar 10 1 >/dev/null

timeout 10s tail -f /dev/null

1
Vous avez "volé" mon idée de délai / timeout .... +1
Rui F Ribeiro

1
Ohhhh mon, merci, j'étais dans une situation sans sommeil, le top est incroyable!
Fire-Dragon-DoL

6

Puisqu'il y a des réponses qui suggèrent d'utiliser l' -t delayoption non standard de read, voici une façon de faire une lecture expirée dans un shell standard:

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

L'argument de stty timeest en dixièmes de seconde.


5

Utilisation de la variable intégrée bash $SECONDSet d'une boucle occupée:

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

2
Cependant, cela ferait une pause d'une durée comprise entre 9 et 10 secondes (en raison d' un bugbash ; zshet mkshavait des problèmes similaires mais ont été corrigés depuis)
Stéphane Chazelas

7
Une bonne façon de faire de la chaleur.
ctrl-alt-delor

6
ce ne sera pas la première fois que je suis accusé d'être plein d'air chaud! :)
Jeff Schaller

4

l'astuce la plus ancienne du livre:

read && echo "This is a test"

Il suffit de frapper Enteret ça va continuer!


Cela ne se produit pas si le processus doit être exécuté sans interaction ou en arrière-plan, n'est-ce pas?
ss_iwe

Correct: Mais ce n'était pas une des exigences du PO selon la question d'origine, donc toujours une réponse valide ... ;-)> :-)
Fabby

1
OP donne spécifiquement un exemple (avec sleep) et demande une alternative équivalente sans. Donc read, n'analyse pas, désolé. ;)
AnoE

@AnoE La réponse de Stéphane est bien sûr la meilleure, la mienne est juste la plus ancienne --- press «enter» to continue --- ;-)
Fabby

4

À l'époque des micro-ordinateurs exécutant BASIC, les retards étaient généralement accomplis avec une boucle vide:

FOR I = 1 TO 10000:NEXT

Le même principe pourrait être utilisé pour insérer un retard dans un script shell:

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

Bien sûr, le problème avec cette approche est que la longueur du retard variera d'une machine à l'autre en fonction de la vitesse de son processeur (ou même sur la même machine sous différentes charges). Contrairement à sleepcela, il optimisera probablement également votre processeur (ou l'un de ses cœurs).


2
Une bonne façon de faire de la chaleur.
ctrl-alt-delor

2
Les boucles de retard sont une idée terrible pour tout sauf pour les périodes de sommeil les plus courtes (quelques nanosecondes ou cycles d'horloge dans un pilote de périphérique) sur n'importe quel processeur moderne pouvant exécuter un système d'exploitation de type Unix. c'est-à-dire un sommeil si court que vous ne pouvez pas faire utilement le CPU faire autre chose en attendant, comme planifier un autre processus ou entrer dans un état de veille à faible puissance avant de se réveiller sur une interruption de minuterie. La fréquence CPU dynamique rend impossible même l'étalonnage d'une boucle de retard pour les comptes par seconde, sauf en tant que retard minimum pouvant dormir beaucoup plus longtemps à basse vitesse d'horloge avant d'augmenter.
Peter Cordes

Les anciens ordinateurs avaient une consommation d'énergie beaucoup moins dépendante de la charge de travail. Les processeurs modernes doivent éteindre dynamiquement différentes parties de la puce autant que possible pour ne pas fondre (par exemple, éteindre des parties des unités d'exécution FPU ou SIMD pendant que seul le code entier est en cours d'exécution, ou au moins transmettre le signal d'horloge à des parties de la puce qui n'ont pas besoin de changer). Et entrer dans un état de veille à faible puissance en mode veille (au lieu de tourner dans une boucle infinie en attente d'interruptions de la minuterie) est également plus récent que les anciens ordinateurs que vous mentionnez.
Peter Cordes

Pour en savoir plus sur l'historique du processeur, voir Modern Microprocessors A 90-Minute Guide! - lighterra.com/papers/modernmicroprocessors .
Peter Cordes

3

Il n'y a pas de fonction intégrée, qui fait la même chose que sleep(sauf si elle sleepest intégrée). Cependant, il existe d'autres commandes qui attendent.

Quelques-uns incluent.

  • atet cron: utilisé pour planifier des tâches à un moment précis.

  • inotifywait: utilisé pour attendre un fichier, ou des fichiers à modifier / supprimer / ajouter / etc


Merci pour cela. Pourriez-vous fournir un exemple pour effectuer une tâche planifiée (dans 10 secondes) avec at?
user321697

1
un montage et un upvote! ;-)
Fabby

cronstocker des tâches crontab, non? Où est atstocké les données planifiées?
user321697

@ user321697 Déjà répondu ici
Fabby

Désolé de revenir à votre édition en Q: vous avez changé le but principal de la question OP qui invaliderait la réponse la plus simple de toutes ... ¯ \ _ (ツ) _ / ¯
Fabby

3

Un classique du pays des fenêtres et des lots:

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

Une mauvaise configuration du pare-feu ou du système de noms peut introduire un délai supplémentaire important.
spectras

1
127.0.0.1 ... @spectras
AnoE

1
Heureusement, ce n'est plus nécessaire, car Windows prend désormais en charge le sommeil en mode natif.
Baldrickk

1
@AnoE> résout la partie système de noms, pas la partie pare-feu. Bien qu'il ne soit pas courant, il peut être configuré pour supprimer silencieusement les pings sur l'interface locale. Cela fera attendre le ping beaucoup plus longtemps.
spectras

+1 pour les souvenirs « fond »
AC

0

Si vous voulez attendre interactivement une nouvelle ligne dans un fichier, alors

tail -f
.

En attente d'une modification sur un système de fichiers? Ensuite, utilisez par exemple

inotify / inoticoming
.

Et il existe d'autres options, selon ce que vous entendez par «attendre».

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.