Dans un script shell, comment puis-je (1) démarrer une commande en arrière-plan (2) attendre x secondes (3) exécuter une deuxième commande pendant l'exécution de cette commande?

11

Voici ce que je dois faire:

  1. démarrer le processus A en arrière-plan
  2. attendez x secondes
  3. démarrer le processus B au premier plan

Comment puis-je faire attendre?

Je constate que le «sommeil» semble tout arrêter et je ne veux pas vraiment «attendre» que le processus A se termine complètement. J'ai vu des boucles basées sur le temps, mais je me demande s'il y a quelque chose de plus propre.

Julie
la source
4
Je vous suggère d'améliorer cette question en fournissant un exemple simple de ce que vous avez déjà essayé.
Andy Dalton
10
D'où avez-vous l'impression que le sleepprocessus A s'arrête? Pouvez-vous montrer le processus de test que vous utilisez ou une sortie indicative de cela? Si processus A est l' arrêt, il est plus probable qu'il essaie de lire à partir du terminal en cours d' exécution en arrière - plan et s'arrêté pour cette raison, plutôt que tout ce qui concerne sleep.
Charles Duffy
3
... si tel est le cas, process_a </dev/null &attachera son stdin à /dev/nullplutôt que le TTY, et cela peut être suffisant pour éviter le problème.
Charles Duffy
D'après mon expérience, le sommeil ne bloquera que le processus en cours et donc pas le processus précédemment démarré en arrière-plan avec &
MADforFUNandHappy

Réponses:

28

À moins que je ne comprenne mal votre question, elle peut simplement être réalisée avec ce court script:

#!/bin/bash

process_a &
sleep x
process_b

(et ajoutez un extra waità la fin si vous voulez que votre script attende pour process_ase terminer avant de quitter).

Vous pouvez même le faire en une ligne, sans avoir besoin d'un script (comme suggéré par @BaardKopperud):

process_a & sleep x ; process_b
dr_
la source
6
Notez que vous n'avez pas besoin bashde cela, n'importe quel shell fera l'affaire, y compris votre système sh, vous n'avez donc pas besoin d'ajouter une dépendance à bash pour votre script.
Stéphane Chazelas
4
Ou tout simplement: process_a & sleep x; process_b
Baard Kopperud
9

Vous pouvez utiliser l' opérateur de contrôle en arrière - plan (&) pour exécuter un processus en arrière-plan et la sleepcommande pour attendre avant d'exécuter un deuxième processus, à savoir:

#!/usr/bin/env bash
# script.sh

command1 &
sleep x
command2

Voici un exemple de deux commandes qui impriment des messages horodatés:

#!/usr/bin/env bash

# Execute a process in the background
echo "$(date) - Running first process in the background..."
for i in {1..1000}; do
    echo "$(date) - I am running in the background";
    sleep 1;
done &> background-process-output.txt &

# Wait for 5 seconds
echo "$(date) - Sleeping..."
sleep 5 

# Execute a second process in the foreground
echo "$(date) - Running second process in the foreground..."
for i in {1..1000}; do
    echo "$(date) - I am running in the foreground";
    sleep 1;
done

Exécutez-le pour vérifier qu'il présente le comportement souhaité:

user@host:~$ bash script.sh

Fri Dec  1 13:41:10 CST 2017 - Running first process in the background...
Fri Dec  1 13:41:10 CST 2017 - Sleeping...
Fri Dec  1 13:41:15 CST 2017 - Running second process in the foreground...
Fri Dec  1 13:41:15 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:16 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:17 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:18 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:19 CST 2017 - I am running in the foreground
Fri Dec  1 13:41:20 CST 2017 - I am running in the foreground
...
...
...
igal
la source
2
La question demande de "démarrer le processus B au premier plan ".
Sparhawk
1
@Sparhawk Wow. Totalement mal lu - aucune explication. Merci pour l'avertissement - code corrigé. Sérieuse nostalgie de votre nom d'utilisateur, btw.
igal
1
Pas de soucis! (De plus, le nom d'utilisateur était à l'origine une référence à ce type , mais je ne me suis rendu compte que plus tard qu'il s'agissait d'un personnage d'Eddings! Et cela me donne envie de relire ces livres…)
Sparhawk
5

J'aime la réponse de @ dr01 mais il ne vérifie pas le code de sortie et vous ne savez donc pas si vous avez réussi ou non.

Voici une solution qui vérifie les codes de sortie.

#!/bin/bash

# run processes
process_a &
PID1=$!
sleep x
process_b &
PID2=$!
exitcode=0

# check the exitcode for process A
wait $PID1    
if (($? != 0)); then
    echo "ERROR: process_a exited with non-zero exitcode" >&2
    exitcode=$((exitcode+1))
fi

# check the exitcode for process B
wait $PID2
if (($? != 0)); then
    echo "ERROR: process_b exited with non-zero exitcode" >&2
    exitcode=$((exitcode+1))
fi
exit ${exitcode}

habituellement je stocke les PID dans un tableau bash, puis la vérification du pid est une boucle for.

Trevor Boyd Smith
la source
2
Vous voudrez peut-être refléter ces codes de sortie dans l'état de sortie de votre script commeA & sleep x; B; ret=$?; wait "$!" || exit "$ret"
Stéphane Chazelas
1
@ StéphaneChazelas bonne idée. j'ai mis à jour le code pour m'assurer qu'un code de sortie différent de zéro est retourné si l'un ou les deux échouent.
Trevor Boyd Smith
L'OP veut process_bcourir au premier plan. Vraisemblablement process_apourrait quitter pendant l' process_bexécution, mais vous pouvez toujours le waitfaire et obtenir l'état de sortie après avoir collecté l'état de sortie du premier plan de process_bla manière normale, $?directement.
Peter Cordes