Як в сценарії оболонки я можу (1) запустити команду у фоновому режимі (2) чекати х секунд (3) виконати другу команду, поки ця команда виконується?


11

Це те, що мені потрібно зробити:

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

Як я можу змусити очікування відбутися?

Я бачу, що "сон", здається, зупиняє все, і я насправді не хочу "чекати", щоб процес A закінчився повністю. Я бачив певні певні години, але мені цікаво, чи є щось чистіше.


4
Я пропоную вам розширити це питання, надавши простий приклад того, що ви вже спробували.
Енді Далтон

10
Звідки у вас складається враження, що sleepзупиняє процес-A? Чи можете ви показати тестовий процес, який ви використовуєте, або вивести вказівку на це? Якщо процес-A є зупинка, це більш ймовірно , що він намагається читати з терміналу в час роботи у фоновому режимі і отримувати зупинився з цієї причини, а не все , що пов'язано з sleep.
Чарльз Даффі

3
... якщо це так, він process_a </dev/null &приєднає свій stdin до /dev/nullTTY, і цього може бути достатньо, щоб уникнути проблеми.
Чарльз Даффі

З мого досвіду сон лише блокує поточний процес, і, таким чином, не той процес, який раніше розпочався у фоновому режимі з &
MADforFUNandHappy

Відповіді:


28

Якщо я не розумію вашого питання, його можна просто досягти за допомогою цього короткого сценарію:

#!/bin/bash

process_a &
sleep x
process_b

(і додайте додаткову waitв кінці, якщо ви хочете, щоб ваш сценарій зачекав, process_aщоб закінчити перед виходом).

Ви навіть можете це зробити як однолінійний без скрипту (як це запропонував @BaardKopperud):

process_a & sleep x ; process_b

6
Зауважте, що для цього вам не потрібно bash, будь-яка оболонка буде включати вашу систему sh, тому вам не потрібно додавати залежність від bash для вашого сценарію.
Стефан Шазелас

4
Або просто: process_a & sleep x; process_b
Баард Копперуд

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 Нічого собі Повністю неправильно прочитав, що - ніяких пояснень. Дякуємо за голову - виправлено код. Серйозна ностальгія за вашим ім'ям користувача, btw.
igal

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 - це цикл.


2
Можливо, ви захочете відобразити такі вихідні коди у статусі виходу вашого сценарію, наприкладA & sleep x; B; ret=$?; wait "$!" || exit "$ret"
Stéphane Chazelas

1
@ StéphaneChazelas хороша ідея. я оновив код, щоб переконатися, що повертається ненульовий код виходу, якщо один або обидва не вдається.
Тревор Бойд Сміт

ОП хоче process_bпрацювати на передньому плані. Імовірно , ви можете process_aвийти під час process_bзапуску, але ви все одно можете waitотримати його та отримати статус виходу після того, як ви зібрали статус виходу з переднього плану process_bзвичайним шляхом, $?безпосередньо.
Пітер Кордес
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.