Прочитать stdout/stderr из подоболочки в родительский поток

Прочитать stdout/stderr из подоболочки в родительский поток

В скрипте оболочки я хочу записать данные в stdin внешнего процесса X, используя именованный канал, и отправить stdout/stderr из другого именованного канала на текущий терминал.

Внешний процесс X получает stdin через PIPEIN и отправляет свой stdout/stderr в PIPEOUT.

tail -f $(tail -F PIPEOUT) &  # (1) this is completely wrong, need help here

for i; do
    echo "${i}" > PIPEIN  # send stdin to X
done

echo "[stdin end]" > PIPEIN  # signal that we are done writing (there might be a better way lol)

Итак, в приведенном выше скрипте мы уже запустили процесс X, он работает уже некоторое время. Но теперь, когда мы запускаем приведенный выше скрипт, мы хотим отправить X некоторый stdin и хотим прочитать stdout из процесса X, используя PIPEOUT.

То, что я пытаюсь сделать выше, — это настроить чтение из PIPEOUT перед отправкой stdin в X, чтобы убедиться, что я захватываю весь stdout/stderr X. Проблема в том, что я не знаю, как запустить какой-нибудь фоновый процесс (tail или cat для чтения из PIPEOUT) и отправить этот stdio в текущий терминал.

Кто-нибудь знает, о чем я говорю. Если я не ошибаюсь, мне просто нужно исправить строку с меткой (1) и как-то настроить чтение в фоновом режиме, которое может читать из PIPEOUT и как-то отправлять это stdio в текущий терминал/tty.

решение1

Я не совсем понимаю, что вы имели в виду tail -f $(tail -F PIPEOUT) &. Это tail -fфайл, которыйявляется результатом tail -F, который обычно никогда не завершается. Я предполагаю, что вы хотите вывести все, что проходит через трубу, сколько бы времени это ни заняло.

Проблема с just tail -fв том, что он должен найти конец файла, прежде чем что-либо вывести, чего для pipe никогда не происходит. Вы можетевместо этого укажите tailявную начальную точку-n +x, выбрав строку, с которой нужно начать (с самого начала, индексация 1). tail -n 1 -f fooотобразит все, что можно получить из foo.

tr 'a-z' 'A-Z' < PIPEIN > PIPEOUT & # for example
tail -n +1 -f PIPEOUT &
for i in a b c d ; do
    echo $i > PIPEIN
done
echo "[stdin end]" > PIPEIN

Однако обратите внимание, что это echo > fooзакроет foo после записи строки — команда на другом конце должна быть счастлива иметь дело с этим. Если этот пример искусственный и реальный ввод поступает откуда-то еще, вы можете проигнорировать это.


Обратите внимание также, чтопроцесс tailникогда не прекратится— он продолжает ожидать, что что-то еще может пройти через канал. Вам придется убить его явно самостоятельно, возможно, с помощью управления заданиями вашей оболочки. Если в выводе есть некоторая закономерность, которая укажет на то, что это было сделано, вы можете обнаружитьretail("хвост с регулярными выражениями")полезно — retail -n +1 -f -u REGEX PIPEOUTзавершится при REGEXпоявлении совпадения строк. (В качестве отказа от ответственности: я написал retailнесколько лет назад именно для этой цели)

решение2

Если открыть PIPEIN для записи только один раз, программа завершится — даже если будет задержка в 2 секунды:

mkfifo PIPEIN PIPEOUT
tr 'a-z' 'A-Z' < PIPEIN > PIPEOUT & # for example
tail -n +1 -f PIPEOUT &
(
for i in a b c d ; do
    echo $i
done
sleep 2
echo "[stdin end]"
) > PIPEIN

Если открыть fifo несколько раз, то читатель fifo может посчитать его закрытым, и, таким образом, писатель будет зависать до тех пор, пока не появится другой читатель, который начнет читать из fifo.

Поэтому спасение — открывать PIPEIN только один раз. В противном случае вы можете увидеть, что программа зависает.

Связанный контент