Как использовать stdout и stderr io-redirection для получения вменяемых сообщений об ошибках / предупреждений из программы? - PullRequest
3 голосов
/ 11 июня 2011

У меня есть программа, которая выводит в stdout и stderr, но не использует их правильно.Некоторые ошибки идут в stdout, некоторые идут в stderr, не связанные с ошибками вещи идут в stderr, и он выводит много информации о stdout.Чтобы это исправить, я хочу сделать конвейер:

  1. Сохранить весь вывод $cmd (из stderr и stdout) в файл $logfile (не выводить его на экран).
  2. Отфильтровать все предупреждения и сообщения об ошибках в stderr и stdout (от предупреждения | ошибка до пустой строки) и раскрасить только слова «ошибки» (перенаправить вывод в stderr).
  3. Сохранить выводшаг 2 к файлу $logfile:r.stderr.
  4. Выход с правильным кодом выхода из команды.

Пока у меня есть это:

$!/bin/zsh
# using zsh 4.2.0
setopt no_multios

# Don't error out if sed or grep don't find a match:
alias -g grep_err_warn="(sed -n '/error\|warning/I,/^$/p' || true)"
alias -g color_err="(grep --color -i -C 1000 error 1>&2 || true)"
alias -g filter='tee $logfile | grep_err_warn | tee $logfile:r.stderr | color_err'

# use {} around command to avoid possible race conditions:
{ eval $cmd } 2>&1 | filter
exit $pipestatus[1]

IЯ пробовал много вещей, но не могу заставить его работать.Я прочитал «От Bash до Z Shell», много постов и т. Д. В настоящее время у меня проблемы:

  1. Только фильтр входит в фильтр

Примечание: $cmd - это сценарий оболочки, который вызывает двоичный файл с префиксом /usr/bin/time -p.Похоже, это вызывает проблемы с конвейерами, и поэтому я обертываю команду в {…}, весь вывод идет в конвейер.

Ответы [ 3 ]

2 голосов
/ 11 июня 2011

У меня нет доступных zsh.

Я заметил, что ваше заявление {..} неверно.

Тебе всегда нужна точка с запятой перед закрывающим `} '.

Когда я добавил это в bash, я смог доказать себе, что stderr перенаправляется на стандартный вывод.

Попробуйте

{ eval $cmd ; } 2>&1 | filter
# ----------^

Также вы написали

Сохранить все выходные данные $ cmd (форма stderr и стандартный вывод) в файл $ logfile

Я не вижу упоминаний о $ logfile в вашем коде. Вы должны быть в состоянии получить весь вывод в лог-файл (при этом теряя специфичность потока stderr), с

yourCommand 2>&1 | tee ${logFile} | ....

Надеюсь, это поможет.

P.S. поскольку вы выглядите новым пользователем, если вы получите ответ, который поможет вам, не забудьте пометить его как принятый и / или дать ему + (или -) как полезный ответ.

1 голос
/ 13 июня 2011

Исходное сообщение было в основном правильным, за исключением оптимизации Жилем (чтобы отключить set -e, поэтому || true не нужны.

#!/bin/zsh
# using zsh 4.2.0
setopt no_multios
#setopt no_errexit # set -e # don't turn this on

{ eval $cmd } 2>&1 |
tee $logfile |
sed -n '/error\|warning/I,/^$/p' |
tee $logfile:r.stderr |
grep --color -i -C 1000 error 1>&2
exit $pipestatus[1]

То, что меня смутило, было смешивание stdout и stderr, которое привело к их чередованию, а sed -n '/error\|warning/I,/^$/p' (который выводит из предупреждения и ошибки || на следующую пустую строку) печатал намного больше, чем ожидалось казалось, что команда не работает.

1 голос
/ 11 июня 2011

Не используйте псевдонимы в скриптах, используйте функции (глобальные псевдонимы особенно ищут проблемы).Не то чтобы вам действительно нужны здесь функции.Вам также не нужно || true (если вы не используете set -e, в этом случае вы должны отключить его здесь).Кроме этого, ваш сценарий выглядит хорошо;что он задыхается?

{ eval $cmd } |
tee $logfile |
sed -n '/error\|warning/I,/^$/p' |
tee $logfile:r.stderr |
grep --color -i -C 1000 error 1>&2
exit $pipestatus[1]

Я также не уверен, что вы имели в виду под выражением sed;Я не совсем понимаю ваше требование 2.

...