Другое

Как перенаправить stderr в pipe, сохраняя stdout

Узнайте, как перенаправить stderr в pipe, сохраняя stdout в Unix/Linux с помощью подстановки процессов. Устраните временные файлы с помощью этой простой техники: команда 2> >(grep шаблон). Полное руководство с примерами.

Как перенаправить stderr в pipe, сохраняя stdout в командах оболочки Unix/Linux?

У меня есть программа, которая записывает информацию в stdout и stderr, и мне нужно обработать stderr с помощью grep, оставив stdout в покое.

Используя временный файл, это можно сделать в два шага:

команда > /dev/null 2> temp.file
grep 'что-то' temp.file

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

Вы можете перенаправить stderr в канал, сохраняя stdout, с помощью подстановки процесса (process substitution) с синтаксисом 2> >(command). Это позволяет отправлять stderr в конвейер без влияния на stdout, устраняя необходимость во временных файлах. Например: command 2> >(grep 'something') передаст stderr в grep, оставив stdout без изменений.

Содержание

Понимание подстановки процессов

Подстановка процессов — это мощная функция оболочки, позволяющая рассматривать вывод команды как временный файл. Синтаксис 2> >(command) специально перенаправляет stderr (дескриптор файла 2) в процесс, оставляя stdout (дескриптор файла 1) без изменений.

Подстановка процесса >(command) создает именованный канал (FIFO), который оболочка управляет автоматически. Когда вы перенаправляете stderr в эту подстановку процесса, команда получает ввод stderr через свой stdin, в то время как исходная команда продолжает записывать в stdout в обычном режиме.

Согласно TLDP Advanced Bash-Scripting Guide, “Перенаправление stdout одной команды в stdin другой — это мощная техника. Но что, если вам нужно перенаправить stdout нескольких команд? Здесь и приходит на помощь подстановка процессов”.

Основной синтаксис и примеры

Основной синтаксис для перенаправления stderr в канал при сохранении stdout:

bash
команда 2> >(обрабатывающая_команда)

Для вашего конкретного случая использования с grep:

bash
команда 2> >(grep 'что-то')

Эта команда будет:

  • Выполнять вашу исходную команду
  • Отправлять весь вывод stderr в grep для фильтрации
  • Полностью оставлять вывод stdout без изменений и доступным для других операций

Дополнительные вариации

Вы можете расширить это с помощью нескольких обрабатывающих команд:

bash
# Отправить stderr в grep, одновременно выводя в консоль
команда 2> >(grep 'что-то' | tee /dev/stderr)

# Сложная обработка с sed
команда 2> >(sed -e 's/^/ОШИБКА: /' | logger -t myapp)

Альтернативные методы с дескрипторами файлов

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

Метод 1: Использование exec для сохранения дескрипторов файлов

bash
exec 3>&1  # Сохранить текущий stdout в дескриптор файла 3
команда 2>&1 1>&3 | grep 'что-то'  # Поменять stderr и stdout местами, затем передать в канал
exec 3>&-   # Очистить дескриптор файла 3

Метод 2: Продвинутое переключение дескрипторов файлов

Как показано в этом ответе на Stack Overflow, вы можете использовать:

bash
{
  команда 2>&1 1>&3 3>&- | команда_stderr
} 3>&1 1>&2 | команда_stdout

Этот подход более сложный, но обеспечивает больший контроль над потоками stdout и stderr.

Практические случаи использования и примеры

Пример 1: Фильтрация сообщений об ошибках

bash
# Найти все файлы, но показывать только ошибки отказа в доступе
find /usr 2> >(grep 'Permission denied')

Это выведет список всех файлов в каталоге /usr, но отобразит только сообщения об ошибках “Permission denied”, в то время как обычные списки файлов будут направлены в stdout.

Пример 2: Логирование ошибок с продолжением обработки

bash
# Запустить приложение, логировать ошибки в syslog, оставить stdout для пользователя
myapp 2> >(logger -t myapp -p user.error)

Пример 3: Извлечение конкретной информации об ошибках

bash
# Извлечь только неудачные подключения из сетевой команды
curl -s https://example.com 2> >(grep 'failed to connect')

Пример 4: Множественная обработка ошибок

bash
# Обрабатывать ошибки разными командами
команда 2> >(grep 'critical' > critical.log) 2> >(grep 'warning' > warning.log)

Сравнение методов

Метод Синтаксис Плюсы Минусы Лучше всего подходит для
Подстановка процессов 2> >(команда) Простой, читаемый, не требует очистки Недоступен во всех оболочках Большинство случаев использования, современные оболочки
Переключение дескрипторов файлов `exec 3>&1; команда 2>&1 1>&3 grep` Работает в старых оболочках Более сложный, требует очистки
**Оператор &** `команда & grep` Очень лаконичный
Отдельные перенаправления 2> >(команда1) > >(команда2) Полный контроль над обоими потоками Самый сложный синтаксис Продвинутая обработка потоков

Метод подстановки процессов обычно предпочитается за его простоту и читаемость, как отмечено в обсуждениях на Server Fault.

Распространенные проблемы и решения

Проблема 1: Порядок подстановки процессов

Если вы настраиваете несколько подстановок процессов, порядок имеет значение:

bash
# НЕПРАВИЛЬНО - обработка stderr получает префикс "stdout: "
exec > >(while read line; do echo " stdout: $line"; done)
exec 2> >(while read line; do echo " stderr: $line"; done)
bash
# ПРАВИЛЬНО - Подстановки процессов в правильном порядке
exec 2> >(while read line; do echo " stderr: $line"; done)
exec > >(while read line; do echo " stdout: $line"; done)

Проблема 2: Совместимость с оболочкой

Подстановка процессов недоступна во всех оболочках. Она работает в:

  • Bash (версия 3.0+)
  • Zsh
  • Ksh

Для совместимости со старыми оболочками, такими как базовый sh, используйте метод с дескрипторами файлов.

Проблема 3: Проблемы с буферизацией

Иногда буферизованный вывод может вызывать задержки. Чтобы обеспечить немедленный вывод:

bash
# Используйте stdbuf или unbuffer для немедленного вывода
stdbuf -o0 -e0 команда 2> >(grep 'что-то')

Заключение

Наиболее эффективный способ перенаправить stderr в канал, сохраняя stdout в Unix/Linux, — это подстановка процессов с использованием синтаксиса 2> >(команда). Этот подход:

  • Полностью устраняет временные файлы
  • Сохраняет stdout без изменений для других операций
  • Предоставляет чистый, читаемый синтаксис, который легко понять
  • Работает с любой обрабатывающей командой, такой как grep, sed, awk и т.д.

Для вашего конкретного случая использования решение простое:

bash
команда 2> >(grep 'что-то')

Эта однострочная команда выполняет именно то, что вам нужно — обрабатывает stderr с помощью grep, оставляя stdout без изменений, все без создания каких-либо временных файлов. Функция подстановки процессов особенно мощна для сценариев оболочки и операций командной строки, где необходимо обрабатывать выходные потоки отдельно.

Источники

  1. TLDP Advanced Bash-Scripting Guide - Подстановка процессов
  2. Unix & Linux Stack Exchange - Подстановка процессов и канал
  3. Stack Overflow - Перенаправление stdout и stderr в два разных процесса
  4. Server Fault - Перенаправление stderr и stdout в разные команды
  5. SS64 - Перенаправление и подстановка процессов
  6. Unix & Linux Stack Exchange - Использование подстановки процессов, только отправка stderr в процесс
Авторы
Проверено модерацией
Модерация