In uno script di shell, come posso (1) avviare un comando in background (2) attendere x secondi (3) eseguire un secondo comando mentre quel comando è in esecuzione?


11

Questo è ciò di cui ho bisogno per accadere:

  1. avviare il processo A in background
  2. attendere x secondi
  3. avvia il processo B in primo piano

Come posso fare aspettare l'attesa?

Sto vedendo che 'sleep' sembra fermare tutto e in realtà non voglio 'aspettare' che il processo A finisca completamente. Ho visto dei loop basati sul tempo ma mi chiedo se c'è qualcosa di più pulito.


4
Ti suggerisco di migliorare questa domanda fornendo un semplice esempio di ciò che hai già provato.
Andy Dalton,

10
Da dove viene l'impressione che sleepblocca il processo A? Puoi mostrare il processo di test che stai utilizzando o un output indicativo di questo? Se il processo A si sta arrestando, è più probabile che stia provando a leggere dal terminale mentre è in esecuzione in background e viene bloccato per quel motivo, piuttosto che a qualsiasi cosa relativa sleep.
Charles Duffy,

3
... se questo è il caso, process_a </dev/null &si attaccherà la sua stdin al /dev/nullpiuttosto che il TTY, e che può essere sufficiente per evitare il problema.
Charles Duffy,

Dalla mia esperienza, sleep bloccherà solo il processo corrente e quindi non il processo precedentemente avviato in background con &
MADforFUNandHappy il

Risposte:


28

A meno che non fraintenda la tua domanda, può essere semplicemente raggiunta con questo breve script:

#!/bin/bash

process_a &
sleep x
process_b

(e aggiungi un extra waitalla fine se vuoi che lo script attenda il process_atermine prima di uscire).

Puoi anche farlo come una linea, senza la necessità di uno script (come suggerito da @BaardKopperud):

process_a & sleep x ; process_b

6
Nota che non ne hai bisogno bash, qualsiasi shell farà compreso il tuo sistema sh, quindi non devi aggiungere una dipendenza da bash per il tuo script.
Stéphane Chazelas,

4
O semplicemente: process_a & sleep x; process_b
Baard Kopperud il

9

È possibile utilizzare l' operatore di controllo in background (&) per eseguire un processo in background e il sleepcomando per attendere prima di eseguire un secondo processo, ovvero:

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

command1 &
sleep x
command2

Ecco un esempio di due comandi che stampano alcuni messaggi timestamp:

#!/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

Eseguilo per verificare che mostri il comportamento desiderato:

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
...
...
...

2
La domanda chiede di "avviare il processo B in primo piano ".
Sparhawk,

1
@Sparhawk Wow. Totalmente frainteso quello - nessuna spiegazione. Grazie per l'heads-up - codice corretto. Grave nostalgia dal tuo nome utente, a proposito.
igal,

1
Nessun problema! (Anche il nome utente era originariamente un riferimento a questo tipo , ma solo successivamente mi sono reso conto che era un personaggio di Eddings! E mi fa venir voglia di rileggere quei libri ...)
Sparhawk il

5

Mi piace la risposta di @ dr01 ma non controlla il codice di uscita e quindi non sai se hai avuto successo o meno.

Ecco una soluzione che controlla i codici di uscita.

#!/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}

di solito memorizzo i PID in un array bash e quindi il controllo pid è un ciclo for.


2
Potresti voler riflettere quei codici di uscita nello stato di uscita del tuo script comeA & sleep x; B; ret=$?; wait "$!" || exit "$ret"
Stéphane Chazelas,

1
@ StéphaneChazelas buona idea. ho aggiornato il codice per assicurarmi che venga restituito un codice di uscita diverso da zero se uno o entrambi non riescono.
Trevor Boyd Smith,

L'OP vuole process_bcorrere in primo piano. Presumibilmente process_apotrebbe uscire mentre process_bè in esecuzione, ma è ancora possibile waitfarlo e ottenere lo stato di uscita dopo aver raccolto lo stato di uscita del primo piano process_bnel modo normale, $?direttamente.
Peter Cordes,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.