Jak w skrypcie powłoki mogę (1) uruchomić polecenie w tle (2) czekać x sekund (3) uruchomić drugie polecenie, gdy to polecenie jest uruchomione?


11

Oto, co muszę zrobić:

  1. rozpocznij proces A w tle
  2. poczekaj x sekund
  3. rozpocznij proces B na pierwszym planie

Jak mogę sprawić, że zacznie się czekać?

Widzę, że „sen” wydaje się zatrzymywać wszystko i nie chcę tak naprawdę „czekać”, aż proces A zakończy się całkowicie. Widziałem pewne pętle oparte na czasie, ale zastanawiam się, czy jest coś czystszego.


4
Sugeruję ulepszenie tego pytania, podając prosty przykład tego, co już wypróbowałeś.
— Andy Dalton,

10
Gdzie masz wrażenie, że sleepzatrzymuje proces A? Czy możesz pokazać proces testowy, którego używasz, lub wynik, który to wskazuje? Jeśli proces-A jest zatrzymanie, to bardziej prawdopodobne, że próbuje odczytać z terminala podczas pracy w tle i coraz zatrzymany z tego powodu, raczej niż cokolwiek związanego sleep.
— Charles Duffy,

3
... czy to jest przypadek, process_a </dev/null &dołączy do jego stdin /dev/nullzamiast TTY, a które mogą być wystarczające, aby uniknąć tego problemu.
— Charles Duffy

Z mojego doświadczenia wynika, że ​​sen blokuje tylko bieżący proces, a zatem nie proces wcześniej rozpoczęty w tle z &
— MADforFUNandHappy

Odpowiedzi:


28

O ile nie rozumiem twojego pytania, można to po prostu osiągnąć za pomocą tego krótkiego skryptu:

#!/bin/bash

process_a &
sleep x
process_b

(i dodaj dodatkową waitna końcu, jeśli chcesz, aby skrypt czekał na process_azakończenie przed zakończeniem).

Możesz to zrobić nawet jako jeden wiersz, bez potrzeby używania skryptu (jak sugeruje @BaardKopperud):

process_a & sleep x ; process_b

6
Zauważ, że nie potrzebujesz bashtego, jakakolwiek powłoka zrobi to włączając twój system sh, więc nie musisz dodawać zależności od bash dla twojego skryptu.
— Stéphane Chazelas,

4
Lub po prostu: process_a & sleep x; process_b
— Baard Kopperud

9

Możesz użyć operatora sterowania w tle (&), aby uruchomić proces w tle, i sleeppolecenia, aby poczekać przed uruchomieniem drugiego procesu, tj .:

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

command1 &
sleep x
command2

Oto przykład dwóch poleceń, które drukują niektóre wiadomości ze znacznikiem czasu:

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

Uruchom go, aby sprawdzić, czy wykazuje pożądane zachowanie:

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
Pytanie dotyczy „rozpoczęcia procesu B na pierwszym planie ”.
— Sparhawk

1
@Sparhawk Wow. Całkowicie źle to przeczytałem - bez wyjaśnienia. Dzięki za heads-up - poprawiony kod. Poważna nostalgia od twojej nazwy użytkownika, btw.
— igal

1
Bez obaw! (Również nazwa użytkownika była pierwotnie odniesieniem do tego faceta , ale dopiero później zdałem sobie sprawę, że była to postać z Eddings! I sprawia, że ​​chcę ponownie przeczytać te książki…)
— Sparhawk

5

Podoba mi się odpowiedź @ dr01, ale on nie sprawdza kodu wyjścia, więc nie wiesz, czy ci się udało, czy nie.

Oto rozwiązanie, które sprawdza kody wyjścia.

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

zwykle przechowuję PID w tablicy bash, a następnie sprawdzanie pid jest pętlą for.


2
Możesz odzwierciedlić te kody wyjścia w stanie wyjścia skryptu, na przykładA & sleep x; B; ret=$?; wait "$!" || exit "$ret"
— Stéphane Chazelas

1
@ StéphaneChazelas dobry pomysł. zaktualizowałem kod, aby upewnić się, że w przypadku niepowodzenia jednego lub obu wystąpi niezerowy kod wyjścia.
— Trevor Boyd Smith

OP chce process_bdziałać na pierwszym planie. Prawdopodobnie process_amożna wyjść, gdy process_bjest uruchomiony, ale nadal możesz waitto zrobić i uzyskać status wyjścia po zebraniu statusu wyjścia na pierwszym planie process_bw normalny sposób, $?bezpośrednio.
— Peter Cordes,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.