Фоновая задача упала, скрипт зелёный: собираем статусы wait по PID
Две независимые проверки запустили параллельно, добавив & после каждой команды. Одна завершилась с ошибкой, другая успешно. Родительский скрипт напечатал «готово» и вернул ноль. Запуск фоновой работы сообщает, что оболочка её создала; он ещё не сообщает результат самой работы.
Чтобы завершение всего скрипта отражало результаты проверок, нужно дождаться каждого дочернего процесса. У Bash для этого есть wait. Вызов без аргументов удобен как ожидание группы, но не заменяет сбор статусов всех участников. Сохраним PID сразу после запуска и разберём результат каждого отдельно.
Воспроизведём успех и отказ
Пример создаёт только два короткоживущих дочерних процесса. Один намеренно возвращает 7. Завершение скрипта должно быть ненулевым независимо от того, какой процесс закончился раньше.
#!/usr/bin/env bash
pids=()
names=()
(sleep 0.1; exit 0) &
pids+=("$!"); names+=(format)
(sleep 0.2; exit 7) &
pids+=("$!"); names+=(validate)
failed=0
for i in "${!pids[@]}"; do
if wait "${pids[$i]}"; then
printf '%s: OK\n' "${names[$i]}"
else
status=$?
printf '%s: exit=%s\n' "${names[$i]}" "$status" >&2
failed=1
fi
done
exit "$failed"
Вы получите format: OK и validate: exit=7, а общий статус будет 1. Исходный код 7 сохранён в диагностике, при этом интерфейс задания прост: ноль, если все проверки успешны, единица при любом отказе. При необходимости можно выбрать другую схему, но нельзя молча отдавать статус последней удачной печати.
$! нужно сохранять сразу: следующий фоновый запуск заменит его. Параллельные массивы связывают PID и понятное имя задачи. На большом наборе лучше оформить такую связь явно и проверить, что каждому запуску соответствует один wait. Потерянный PID означает потерянный результат проверки.
Порядок ожидания не отменяет параллельность
Цикл ждёт PID в порядке запуска. Это не делает задачи последовательными: оба дочерних процесса уже работают. Если первая задача долгая, сообщение о второй появится позже её фактического завершения. Для короткой группы проверок такой порядок часто приемлем и делает отчёт стабильным.
В современных Bash есть wait -n для ожидания следующей завершившейся задачи. Он полезен для пула ограниченного размера, но требует отдельного учёта, какой PID завершился, и проверки доступности нужных опций в установленной версии. Не добавляйте эту сложность только ради двух независимых команд.
Логи задач могут перемешиваться, если обе пишут в один терминал. В рабочем скрипте выделите им отдельные файлы и печатайте итог с именем задачи. Тогда можно открыть диагностику конкретного отказа, не восстанавливая порядок строк по времени. Имена файлов логов должны принадлежать текущему запуску, чтобы старый результат не выглядел свежим.
Решите политику после первого отказа
Пример ждёт всех участников даже после ошибки. Это подходит для независимых проверок: инженер получает полный список проблем за один запуск. Для связанных операций может потребоваться отменить оставшуюся работу, но тогда нужно послать сигнал конкретным сохранённым PID, дождаться их завершения и обработать собственную очистку. Простого exit родителя для этого недостаточно.
Параллельно запускайте лишь задачи, которые действительно независимы. Если одна перезаписывает вход другой или обе меняют один результат, сбор статусов не устранит гонку. Сначала разделите выходные файлы либо задайте зависимость, а затем выбирайте число одновременных исполнителей.
В курсе Linux и Bash проверка ошибок связана с автоматизацией повседневных операций. Откройте программу и продолжите от фоновых проверок к скрипту сопровождения, который ждёт работу до конца, сохраняет диагностику и выдаёт надёжный итог расписанию.
Ещё по теме
Продолжить на практике
- Linux и Bash для DevOps-инженеров ↗
Linux для работы с серверами: процессы, права, systemd, сеть, диски и логи. Автоматизируйте повседневные задачи на Bash и разберите типичные сбои сервиса — от занятого порта до переполненного диска.
