Как к grep потоку стандартной погрешности (stderr)?

Можно создать псевдоним для sudo + название сценария. Конечно, это - еще больше работы для установки, так как затем необходимо установить псевдоним также, но она сохраняет Вас от необходимости ввести sudo.

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

Позвольте мне заявить, что я советую против фактического выполнения этого, все же. Я просто упоминаю это в образовательных целях ;-)

81
31.10.2010, 07:25
9 ответов

Если Вы используете bash почему бы не использовать неименованные каналы, в сущности сокращение от какой сказанный phunehehe:

ffmpeg -i 01-Daemon.mp3 2> >(grep -i Duration)

57
27.01.2020, 19:30
  • 1
    +1! Bash только, но путь инструмент для очистки, чем альтернативы. –  Mikel 08.02.2011, 03:43
  • 2
    +1 я использовал это для проверки cp вывод cp -r dir* to 2> >(grep -v "svn") –  Betlista 15.08.2014, 17:08
  • 3
    Если Вы хотите фильтрованный перенаправленный вывод на stderr снова, добавьте a >&2, например. command 2> >(grep something >&2) –  tlo 06.05.2016, 12:16

Ни одна из обычных оболочек (даже zsh) не разрешает каналы кроме от stdout до stdin. Но весь стиль Границы окружает переназначение дескриптора файла поддержки (как в 1>&2). Таким образом, можно временно отклонить stdout к fd 3 и stderr к stdout, и позже отложить fd 3 на stdout. Если stuff производит некоторый вывод на stdout и некоторый вывод на stderr, и Вы хотите подать заявку filter на выводе ошибок, оставляя стандартный вывод нетронутым, можно использовать { stuff 2>&1 1>&3 | filter 1>&2; } 3>&1.

$ stuff () {
  echo standard output
  echo more output
  echo standard error 1>&2
  echo more error 1>&2
}
$ filter () {
  grep a
}
$ { stuff 2>&1 1>&3 | filter 1>&2; } 3>&1
standard output
more output
standard error
48
27.01.2020, 19:30
  • 1
    Этот подход работы. К сожалению, в моем случае, если ненулевое возвращаемое значение возвращается, оно теряется - возвращенное значение 0 для меня. Этого не может всегда происходить, но это происходит в случае, на который я в настоящее время смотрю. Там какой-либо путь состоит в том, чтобы сохранить его? –  Faheem Mitha 27.04.2016, 01:08
  • 2
    @FaheemMitha, Не уверенный, что Вы делаете, но возможно pipestatus помог бы –  Gilles 'SO- stop being evil' 27.04.2016, 02:15
  • 3
    @FaheemMitha, также set -o pipefail может быть полезным здесь, в зависимости от того, что Вы хотите сделать с ошибочным состоянием. (Например, если Вы имеете set -e включенный для сбоя на любых ошибках Вы, вероятно, хотите set -o pipefail также.) –  Wildcard 27.04.2016, 02:21
  • 4
    @Wildcard Да, я имею set -e включенный для сбоя на любых ошибках. –  Faheem Mitha 27.04.2016, 02:33

Это подобно "временному приему файла phunehehe", но использует именованный канал вместо этого, позволяя Вам получить результаты немного ближе к тому, когда они производятся, который может быть удобным для продолжительных команд:

$ mkfifo mypipe
$ command 2> mypipe | grep "pattern" mypipe

В этой конструкции stderr будет направлен к каналу, названному "mypipe". С тех пор grep был назван с аргументом файла, он не будет смотреть на STDIN для своего входа. К сожалению, необходимо будет все еще очистить тот именованный канал, после того как Вы сделаны.

При использовании Bash 4 существует синтаксис ярлыка для command1 2>&1 | command2, который является command1 |& command2. Однако я полагаю, что это - просто ярлык синтаксиса, Вы все еще перенаправляете STDERR к STDOUT.

21
27.01.2020, 19:30

Gilles и ответы Stefan Lasiewski оба хороши, но этот путь более прост:

ffmpeg -i 01-Daemon.mp3 2>&1 >/dev/null | grep "pattern"

Я предполагаю, что Вы не хотите ffmpeg's stdout распечатан.

Как это работает:

  • каналы сначала
    • ffmpeg и grep запускаются с stdout ffmpeg, идущим в stdin grep
  • перенаправления затем, слева направо
    • stderr ffmpeg установлен на то, что его stdout (в настоящее время канал)
    • stdout ffmpeg установлен на/dev/null
10
27.01.2020, 19:30
  • 1
    , Это описание сбивает с толку меня. Последние два маркера заставляют меня думать "перенаправление stderr к stdout", затем "перенаправляют stdout (с stderr, теперь) к/dev/null". Однако это не то, что это действительно делает. Те операторы, кажется, инвертируются. –  Steve 24.09.2015, 18:15
  • 2
    @Steve Там не "с stderr" во втором маркере. Вы видели unix.stackexchange.com/questions/37660/order-of-redirections? –  Mikel 24.09.2015, 18:30
  • 3
    Нет, я подразумеваю, что это - моя интерпретация того, как Вы описали ее на английском языке. Ссылка, которую Вы предоставили, очень полезна, все же. –  Steve 24.09.2015, 20:50

Посмотрите ниже для сценария, используемого в этих тестах.

Grep может только воздействовать на stdin, поэтому необходимо преобразовать stderr поток в форме, которую может проанализировать Grep.

Обычно, stdout и stderr оба печатаются на Ваш экран:

$ ./stdout-stderr.sh
./stdout-stderr.sh: Printing to stdout
./stdout-stderr.sh: Printing to stderr

Чтобы скрыть stdout, но все еще распечатать stderr делают это:

$ ./stdout-stderr.sh >/dev/null
./stdout-stderr.sh: Printing to stderr

Но grep не будет воздействовать на stderr! Вы ожидали бы, что следующая команда подавит строки, которые содержат, 'допускают ошибку', но она не делает.

$ ./stdout-stderr.sh >/dev/null |grep --invert-match err
./stdout-stderr.sh: Printing to stderr

Вот решение.

Следующий синтаксис Bash скроет вывод к stdout, но все еще покажет stderr. Сначала мы передаем stdout по каналу к/dev/null, затем мы преобразовываем stderr в stdout, потому что каналы Unix будут только воздействовать на stdout. Вы можете все еще grep текст.

$ ./stdout-stderr.sh 2>&1 >/dev/null | grep err
./stdout-stderr.sh: Printing to stderr

(Обратите внимание, что вышеупомянутая команда отличается затем ./command >/dev/null 2>&1, который является очень общей командой).

Вот сценарий, используемый для тестирования. Это печатает одну строку к stdout и одну строку к stderr:

#!/bin/sh

# Print a message to stdout
echo "$0: Printing to stdout"
# Print a message to stderr
echo "$0: Printing to stderr" >&2

exit 0
7
27.01.2020, 19:30
  • 1
    Если Вы передвигаете перенаправления, Вам не нужны все фигурные скобки. Просто сделайте ./stdout-stderr.sh 2>&1 >/dev/null | grep err. –  Mikel 08.02.2011, 03:45

Когда Вы передаете вывод по каналу одной команды другому (использование |), Вы только перенаправляете стандартный вывод. Таким образом, это должно объяснить почему

ffmpeg -i 01-Daemon.mp3 | grep -i Duration

не производит то, что Вы хотели (это действительно работает, хотя).

Если Вы не хотите перенаправлять вывод ошибок к стандартному выводу, можно перенаправить вывод ошибок в файл, то grep он позже

ffmpeg -i 01-Daemon.mp3 2> /tmp/ffmpeg-error
grep -i Duration /tmp/ffmpeg-error
3
27.01.2020, 19:30
  • 1
    Спасибо. it does work, though, Вы подразумеваете, что это работает над Вашей машиной? Во-вторых, поскольку Вы указали на канал использования, мы можем только перенаправить stdout. Я интересуюсь некоторой командой или функцией удара, которая позволит мне перенаправить stderr. (но не временный прием файла) –  Andrew-Dufresne 26.10.2010, 07:07
  • 2
    @Andrew, который я имею в виду, работы команды путем, это было разработано для работы. Это просто не работает способ, которым Вы хотите это к :) –  phunehehe 26.10.2010, 07:25
  • 3
    , который я не знаю никакого пути, который может перенаправить вывод ошибок команды к стандартному входу другого. Было бы интересно, если кто-то может указать на это. –  phunehehe 26.10.2010, 07:31

попробуйте эту команду

  • создайте файл со случайным именем
  • отправьте вывод в файл
  • отправьте содержание файла для передачи по каналу
  • grep

Чева-> просто имя переменной (английский язык = что-то)

ceva=$RANDOM$RANDOM$RANDOM; ffmpeg -i qwerty_112_0_0_record.flv 2>$ceva; cat $ceva | grep Duration; rm $ceva;
-1
27.01.2020, 19:30

Вариант примера подпроцесса bash:

выведите две строки в stderr и tee stderr в файл, grep тройник и труба обратно на stdout

(>&2 echo -e 'asdf\nfff\n') 2> >(tee some.load.errors | grep 'fff' >&1)

stdout:

fff

some.load.errors (например, stderr):

asdf
fff
0
27.01.2020, 19:30

Вы можете поменять потоки местами. Это позволит вам grep оригинальный поток стандартной ошибки, получая при этом вывод, который изначально шел на стандартный вывод в терминале:

somecommand 3>&2 2>&1 1>&3- | grep 'pattern'

Это работает путем создания нового файлового дескриптора (3), открытого для вывода, и установки его на поток стандартной ошибки (3>&2). Затем мы перенаправляем стандартную ошибку на стандартный вывод (2>&1). Наконец, стандартный вывод перенаправляется на исходную стандартную ошибку, а новый дескриптор файла закрывается (1>&3-).

В вашем случае:

ffmpeg -i 01-Daemon.mp3 3>&2 2>&1 1>&3- | grep -i Duration

Проверяем:

$ ( echo "error" >&2; echo "output" ) 3>&2 2>&1 1>&3- | grep "error"
output
error

$ ( echo "error" >&2; echo "output" ) 3>&2 2>&1 1>&3- | grep -v "error"
output
3
27.01.2020, 19:30

Теги

Похожие вопросы