Exécuter la commande après un certain laps de temps?

24

Si j'exécute un long processus, est-il possible d'exécuter des commandes temporelles?

Par exemple, j'exécute un processus très long qui dure environ 10 minutes.

Après 5 minutes, je voudrais exécuter une commande distincte. À titre d'illustration, la commande distincte pourrait être:echo 5 minutes complete

(Remarque: je ne veux pas de progrès vers l'achèvement de la commande, mais simplement des commandes exécutées après des intervalles spécifiés.)

C'est possible?

Aniket Bhattacharyea
la source
1
La plupart du temps, vous ne savez pas à l'avance combien de temps prendra un processus.
choroba
Que voulez-vous dire par "commandes basées sur le temps"? Voulez-vous créer une barre de progression? Sur la base de la formulation actuelle de votre question, vous pouvez simplement mettre la commande de longue durée en arrière-plan, puis afficher l'horloge système. Précisez s'il vous plaît.
Wildcard
@Wildcard J'ai clarifié la question. Pas une barre de progression. Il exécutera les commandes après quelques intervalles
Aniket Bhattacharyea
1
"5 minutes complètes" est une chose étrange à répéter. Pas "5 minutes se sont écoulées"? Pas "L'heure est _____"? Voulez-vous simplement vous assurer qu'un intervalle de temps spécifié s'est écoulé depuis le moment où votre commande de longue durée a été lancée, avant qu'une autre commande arbitraire ne soit exécutée? Si oui, pourquoi ne pas simplement courir longcommand & sleep 300 && command-to-do-after-five-minutes? (En fait, c'est probablement ce que vous recherchez.) Notez que votre clarification n'était pas suffisante, car vous avez obtenu deux implémentations de barre de progression d'horloge dès le départ.
Wildcard

Réponses:

30

Exécutez simplement:

long-command & sleep 300; do-this-after-five-minutes

Le do-this-after-five-minutessera exécuté après cinq minutes. Le long-commandsera exécuté en arrière-plan.

Caractère générique
la source
10
J'utilise habituellement sleep 5m && foobar, donc si je change d'avis et ^ C la sleep, la commande suivante ne s'exécute pas.
Peter Cordes
@PeterCordes, quand je l'ai testé avec par exemple sleep 3; lset ^C, la deuxième commande ne s'exécute pas de toute façon. Vous ne savez pas vraiment pourquoi et cela fonctionne peut-être différemment dans un shell non interactif?
Wildcard
1
@PeterCordes Pas tout à fait - à moins qu'il ne diffère par shell. Lorsque vous sleep 5m && echodormez, lorsque vous suspendez, seule la sleepcommande est suspendue. Le reste de la ligne de commande s'exécute, mais depuis qu'il a sleepété suspendu, il ne s'est pas terminé avec succès et la partie suivante &&est ignorée. Essayez de suspendre sleep 5 || echo helloet hellos'affiche directement après avoir appuyé sur ^Z.
DVD
1
@hvd: Oui, vous avez raison et je me trompe à nouveau>. <, en utilisant bash4. Apparemment, cela fait trop longtemps que j'ai décidé que && était la voie à suivre en tant que ghetto at(1), pour des choses comme le sleep 30m && mplayer something.mp3rappel d'alarme ou pour sleep 90m && fgreprendre une commande gourmande en disque plus tard. Donc, en fait, sleep 5m && echo helloc'est bien parce que ^Zsuspend sleepsans exécuter la commande suivante du tout. Si vous souhaitez pouvoir suspendre / reprendre l'intégralité de la commande composée, avant même la fin du sommeil, utilisez ( sleep 2 && echo hello ).
Peter Cordes
@hvd: L' &&idiome vous permet d'être absolument sûr de ne pas tuer le processus juste après la mise en veille (car vous pouvez ^Zne pas exécuter la commande, au lieu de risquer a ^C). Ceci est utile dans le cas d'utilisation sleep && fgou sleep && bg, lorsque la commande reprise reprend à mi-chemin quelque chose de lent.
Peter Cordes
5

Vous pouvez utiliser ce script:

#!/bin/bash

TEMPFILE="$(mktemp)"
STARTTIME="$(date +%s)"
(./longprocess; rm -f "$TEMPFILE") &
while [ -f "$TEMPFILE" ]; do
    sleep 1s
    NOW="$(date +%s)"
    if (( (NOW-STARTTIME) % 300 == 0 )); then
        echo "$(( (NOW-STARTTIME)/60 )) minute(s) elapsed"
    fi
done
echo "Done!!!"

Il exécute votre fichier longprocessdans un sub-shell, puis surveille l'existence du fichier de «verrouillage» créé précédemment.

Serge
la source
2
Vérifiez man bashpour SECONDS. Vous pouvez définir SECONDS=0au démarrage du script et ne vérifier que supérieur ou égal à 300 ou définir SECONDS=$((date +%s))et oublier d'utiliser à datenouveau dans votre script ...
@yeti, merci pour l'astuce, je ne le savais pas.
Serge
@yeti, si vous voulez vous fier au temps après avoir sleep 1stoujours été exactement une seconde plus tard qu'auparavant sleep 1s... alors vous avez été victime de faussetés que les programmeurs croient au temps . (Bien que dans ce cas, vous pourriez tout aussi bien afficher une barre de progression de marque de hachage ou quelque chose comme ça.)
Wildcard
@Wildcard ... Je n'ai rien mentionné sleepdu tout!
@yeti, vous avez raison. Merci pour le conseil SECONDS! :)
Wildcard
4

Il y a une doublure pour cela:

( ( sleep $TIMEOUT ; echo "5 minutes complete") & $COMMAND )

Dans votre cas TIMEOUT = 5m et COMMAND est la commande longue.

Voir également ma réponse à ce message Délai d'attente avec «redémarrage du réseau de service»

coffeMug
la source
Lancer un sous-shell au premier plan puis exécuter la commande semble inutilement compliqué. Je supprimerais les parenthèses externes et l'exec.
glenn jackman
1
@glennjackman De cette façon, on peut tuer toute la procédure en envoyant CTRL + C (par exemple) au sous-shell principal (le plus externe).
coffeMug
1
Mais en utilisant exec, vous n'avez plus de sous-shell, vous avez juste la commande. Le parent de la commande est le shell exécutant le script comme si vous n'aviez pas du tout utilisé de sous-shell.
glenn jackman
3
#! /bin/bash

( sleep 4 ) & # <-- The long running process.

seconds=1
while jobs %1 &>/dev/null ; do
    echo $((seconds++)) seconds complete
    sleep 1    
done
echo Done.

jobs %1 échoue une fois le travail% 1 arrêté.

Notez que pour des temps plus longs, $ secondes peuvent se désynchroniser avec le temps réel. Il est préférable de stocker l'heure de début et de calculer la différence avec l'heure réelle.

choroba
la source