В сценарии оболочки, как я могу (1) запустить команду в фоновом режиме (2) подождать x секунд (3) выполнить вторую команду во время выполнения этой команды?

11

Вот что мне нужно, чтобы это произошло:

  1. начать процесс А в фоновом режиме
  2. ждать х секунд
  3. начать процесс B на переднем плане

Как я могу заставить ожидание случиться?

Я вижу, что «сон», кажется, останавливает все, и я на самом деле не хочу «ждать», пока процесс А завершится полностью. Я видел циклы, основанные на времени, но мне интересно, есть ли что-нибудь чище.

Julie
источник
4
Я предлагаю вам расширить этот вопрос, предоставив простой пример того, что вы уже пробовали.
Энди Далтон
10
Откуда у вас складывается впечатление, что sleepостанавливает процесс А? Можете ли вы показать процесс тестирования, который вы используете, или вывести показательный результат? Если процесс-A является остановка, это более вероятно , что он пытается читать с терминала во время работы в фоновом режиме и получать остановился по этой причине, а не все , что связано с sleep.
Чарльз Даффи
3
... если это так, то process_a </dev/null &присоединит его стандартный ввод , /dev/nullа не TTY, и это может быть достаточно , чтобы избежать этой проблемы.
Чарльз Даффи
Исходя из моего опыта, сон будет блокировать только текущий процесс и, следовательно, не процесс, ранее запущенный в фоновом режиме с &
MADforFUNandHappy

Ответы:

28

Если я не понимаю ваш вопрос, его можно просто выполнить с помощью этого короткого сценария:

#!/bin/bash

process_a &
sleep x
process_b

(и добавьте дополнительный waitв конце, если вы хотите, чтобы ваш скрипт ждал process_aзавершения, прежде чем выйти).

Вы даже можете сделать это как однострочник, без необходимости сценария (как предложено @BaardKopperud):

process_a & sleep x ; process_b
dr_
источник
6
Обратите внимание, что для этого вам не нужно bash, подойдет любая оболочка, включая вашу систему sh, поэтому вам не нужно добавлять зависимость от bash для вашего скрипта.
Стефан
4
Или просто: process_a & sleep x; process_b
Baard Kopperud
9

Вы можете использовать оператор фонового управления (&) для запуска процесса в фоновом режиме и sleepкоманду для ожидания перед запуском второго процесса, а именно:

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

command1 &
sleep x
command2

Вот пример двух команд, которые выводят сообщения с метками времени:

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

Запустите его, чтобы убедиться, что он демонстрирует желаемое поведение:

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
Вопрос просит «запустить процесс B на переднем плане ».
Sparhawk
1
@ Sparhawk Вау. Совершенно неверно истолковано это - без объяснения причин. Спасибо за хедз-ап - код исправлен. Серьезная ностальгия по вашему имени пользователя, кстати.
Игаль
1
Не волнуйтесь! (Также имя пользователя изначально было ссылкой на этот раздел , но я только позже понял, что это персонаж Эддинга! И я хочу перечитать эти книги…)
Sparhawk
5

Мне нравится ответ @ dr01, но он не проверяет код выхода, и поэтому вы не знаете, успешны ли вы или нет.

Вот решение, которое проверяет коды выхода.

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

обычно я сохраняю PID в массиве bash, а затем проверка pid является циклом for.

Тревор Бойд Смит
источник
2
Возможно, вы захотите отразить эти коды выхода в статусе выхода вашего скрипта, напримерA & sleep x; B; ret=$?; wait "$!" || exit "$ret"
Стефан
1
@ StéphaneChazelas хорошая идея. я обновил код, чтобы убедиться, что в случае сбоя одного или обоих кодов возвращается ненулевой код выхода.
Тревор Бойд Смит
ОП хочет process_bработать на переднем плане. Предположительно process_aможет выйти, когда process_bработает, но вы все равно можете waitполучить его и получить статус выхода после того, как вы получили статус выхода на переднем плане process_bобычным способом, $?напрямую.
Питер Кордес