Как выйти из пайплайна (command1 | command2), сохранив при этом работающий в фоновом режиме подпроцесс, запущенный командой command1?

Вопрос или проблема

Относительно команды cmd1.sh | grep "message", в которой cmd1.sh выглядит следующим образом:

#!/bin/bash
echo "message from foreground father process"
setsid sleep 100 &
echo "foreground father process quits"
  1. cmd1.sh выводит сообщение
  2. запускает фоновый подпроцесс
  3. затем снова заканчивается сообщением
  4. завершается, оставляя фоновый подпроцесс sleep 100 активным

Вы обнаружите, что cmd1.sh работает хорошо, но cmd1.sh | grep "message" зависает, и я понимаю, что это происходит потому, что подпроцесс подключается к каналу.

Так что может ли кто-нибудь из экспертов предложить решение, чтобы выйти из cmd1.sh | grep "message", не изменяя cmd1.sh?

(На самом деле моя конкретная проблема связана с pg_ctl restart | grep "blabla", где pg_ctl — это бинарный файл, запускающий postgres)

Ответ или решение

Чтобы решить проблему, связанную с командой cmd1.sh | grep "message", и избежать блокировки выполнения, представляю вам подробное описание процесса и решение. Ваша цель — выполнить пайплайн, при этом оставив фоновый процесс, запущенный командой cmd1.sh, работающим.

Исходная проблема

Скрипт cmd1.sh выполняет следующие действия:

  1. Выводит сообщение в консоль.
  2. Запускает фоновый процесс sleep 100 через setsid, что изолирует его в отдельной сессии.
  3. Завершает выполнение с выводом финального сообщения.

При запуске cmd1.sh напрямую, всё работает корректно, и фоновый процесс остается активным. Однако выполнение через пайплайн cmd1.sh | grep "message" вызывает зависание, поскольку поток вывода пайплайна взаимодействует с дочерними процессами.

Корень проблемы

Проблема заключается в унаследованной связи стандартных потоков между командой grep и фоновым процессом, который создается скриптом cmd1.sh. Пайплайн создает блокировку, поскольку grep продолжает ожидать ввода данных до завершения всех задействованных процессов.

Решение задачи

Для решения данной проблемы, не изменяя содержимое cmd1.sh, можно воспользоваться следующим подходом:

  1. Изолировать процесс cmd1.sh от пайплайна: Используйте команду stdbuf или подобные методы для управления буферизацией ввода-вывода. Это позволит избежать блокировки.

  2. Использовать конструкцию nohup, для того чтобы фоновый процесс продолжал свою работу после завершения всех стандартных потоков.

Пример решения выглядит следующим образом:

( cmd1.sh & echo "Process launched" ) | stdbuf -o0 grep "message"

Детали решения

  • Подчеркивание независимости: Оболочка запускает cmd1.sh в фоновом режиме, а echo "Process launched" позволяет ‘освободить’ пайплайн, завершая передачу данных в стандартный вывод и предоставляя grep конкретный набор данных для обработки.

  • Использование stdbuf: Укомплектовывает буферизацию, предотвращая лишнее накапливание данных в стеке.

Эта довольно простая инженерная комбинация позволяет обойти проблему блокировки, давая возможность успешно интерпретировать команды в пайплайне, и при этом фоновый процесс, запущенный cmd1.sh, продолжает функционировать без влияния на общий поток выполнения.

Поэтому, вредные навязчивые состояния процесса и блокировки будут эффективно устранены данным подходом.

Оцените материал
Добавить комментарий

Капча загружается...