Вопрос или проблема
Возьмите следующий 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
для чтения их содержимого и перенаправления в другой процесс.
Заключение
Оба подхода имеют свои преимущества, и выбор зависит от конкретной задачи. Использование перенаправления потоков в одном дескрипторе является более простым и быстрым вариантом, в то время как именованные каналы могут быть предпочтительными для более сложных или асинхронных сценариев. Выберите тот метод, который лучше всего соответствует вашим нуждам в данной ситуации.