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.