Как перенаправить все потоки вывода в другой процесс?

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

Возьмите следующий Bash скрипт 3-output-writer.sh:

echo A >&1
echo B >&2
echo C >&3

Когда вы запускаете его как . 3-output-writer.sh, возникает ошибка 3: Неверный дескриптор файла, потому что Bash не знает, что делать с третьим потоком вывода. Однако можно легко выполнить . 3-output-writer.sh 3>file.txt, и Bash будет рад.

Но вот вопрос: как перенаправить все эти потоки в другой процесс, чтобы у него было с чем работать? Есть ли какой-то способ помимо создания трех именованных каналов, например, так:

mkfifo pipe1 pipe2 pipe3  # подготовить каналы
. 3-output-writer.sh 1>pipe1 2>pipe2 3>pipe3 &  # запустить запись в фоновом режиме, ожидая читателей
3-input-reader pipe1 pipe2 pipe3  # какой-то читатель, осторожно, чтобы не заблокироваться
rm pipe1 pipe2 pipe3

?

Если вы хотите, чтобы вывод нескольких команд был передан в одну другую команду, проще всего сделать так, чтобы они записывали их в один и тот же дескриптор, который идет в этот канал:

{
  echo A
  echo B
  echo C
} | cmd

Если эти команды записывают в разные дескрипторы, чем их стандартный вывод, вы можете сделать так, чтобы эти дескрипторы ссылались на одно и то же открытое файловое описание, открытое на канале с помощью:

{
  echo A
  echo B >&2
  echo C >&3
} 2>&1 3>&1 | cmd

Обратите внимание, что echo всегда записывает в свой дескриптор 1. С помощью echo C >&3 он все равно выводится на дескриптор 1, но этот дескриптор 1 был настроен так, чтобы ссылаться на одно и то же открытое файловое описание, как и дескриптор 3. print -u3 C (где print является встроенной командой ksh или zsh (bash тоже имеет аналог в виде загружаемого встроенного)) был бы реальным примером команды, которая записывает в свой дескриптор 3.

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

Чтобы перенаправить все выходные потоки (stdout, stderr и дополнительные потоки) в другой процесс в Bash, можно использовать несколько подходов. Вот подробное решение на ваш вопрос.

Решение

Рассмотрим ситуацию с вашим скриптом 3-output-writer.sh, который создает несколько потоков вывода:

echo A >&1
echo B >&2
echo C >&3

где echo A идет в стандартный выход (stdout), echo B идет в стандартный инструмент диагностики (stderr), а echo C пишет в третий поток.

Способ 1: Перенаправление потоков в один и тот же файл-дескриптор

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

{
  echo A
  echo B >&2
  echo C >&3
} 2>&1 3>&1 | ваш_процесс

Здесь:

  • Сначала мы оборачиваем команды в фигурные скобки { ... }, что позволяет сгруппировать несколько команд и отправить их вывод.
  • 2>&1 перенаправляет stderr (2) на stdout (1).
  • 3>&1 перенаправляет третий поток (3) также на stdout.

Таким образом, все три потока будут направлены в ваш процесс, например, ваш_процесс.

Способ 2: Использование именованных каналов (FIFO)

Если вы предпочитаете более устойчивое решение или хотите обрабатывать потоки асинхронно, вы можете создать именованные каналы (FIFO):

mkfifo pipe1 pipe2 pipe3  # создаем именованные каналы
. 3-output-writer.sh 1>pipe1 2>pipe2 3>pipe3 &  # запускаем ваш скрипт в фоновом режиме

# Чтение из всех каналов
cat pipe1 pipe2 pipe3 | ваш_процесс

# Удаляем именованные каналы
rm pipe1 pipe2 pipe3

Этот способ включает в себя создание трех именованных каналов, в которые ваш скрипт будет записывать свои потоки. Затем вы можете использовать cat для чтения их содержимого и перенаправления в другой процесс.

Заключение

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

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

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