У меня есть программа, которая записывает информацию в stdout
и stderr
, и мне нужно grep
пройти через то, что поступает в stderr , игнорируя stdout .
Конечно, я могу сделать это в 2 этапа:
command > /dev/null 2> temp.file
grep 'something' temp.file
но я бы предпочел иметь возможность делать это без временных файлов. Есть ли какие-нибудь хитрые хитрости?
command 2| othercommand
. Bash настолько совершенен, что разработка закончилась в 1982 году, поэтому, боюсь, мы никогда этого не увидим.Ответы:
Сначала перенаправьте stderr в stdout - канал; затем перенаправить stdout
/dev/null
(без изменения куда идет stderr):Подробнее о перенаправлении ввода / вывода во всех его разновидностях см. Главу о перенаправлениях в справочном руководстве Bash.
Обратите внимание, что последовательность перенаправлений ввода / вывода интерпретируется слева направо, но каналы устанавливаются до того, как перенаправления ввода / вывода будут интерпретированы. Файловые дескрипторы, такие как 1 и 2, являются ссылками на описания открытых файлов. Операция
2>&1
заставляет файловый дескриптор 2, также известный как stderr, ссылаться на то же самое описание открытого файла, что и файловый дескриптор 1, также известный как stdout, в данный момент ссылается (см.dup2()
Иopen()
). Затем операция>/dev/null
изменяет дескриптор файла 1 так, чтобы он ссылался на описание открытого файла/dev/null
, но это не меняет того факта, что дескриптор файла 2 ссылается на описание открытого файла, на которое первоначально указывал дескриптор файла 1, а именно на канал.источник
command 2> /dev/stdout 1> /dev/null | grep 'something'
/dev/stdout
et al, или использовать/dev/fd/N
. Они будут незначительно менее эффективны, если оболочка не будет рассматривать их как особые случаи; Чистая числовая запись не предполагает доступа к файлам по имени, но использование устройств означает поиск имени файла. Если вы можете измерить это спорно. Мне нравится краткость числовых обозначений - но я использую их так долго (более четверти века; ах!), Что я не обладаю достаточной квалификацией, чтобы судить о ее достоинствах в современном мире.2>&1
, что означает «подключить stderr к дескриптору файла, к которому в данный момент идет stdout ». Вторая операция - «изменить стандартный вывод так, чтобы он пошел/dev/null
», оставив стандартный вывод на исходный стандартный канал - канал. Оболочка сначала разбивает объекты по символу канала, поэтому перенаправление канала происходит перед2>&1
или>/dev/null
перенаправлениями, но это все; другие операции слева направо. (Справа налево не будет работать.)/dev/null
в эквивалент Windowsnul
).Или для замены вывода из стандартной ошибки и стандартного вывода используйте:
Это создает новый файловый дескриптор (3) и назначает его в то же место, что и 1 (стандартный вывод), затем назначает fd 1 (стандартный вывод) в то же место, что и fd 2 (стандартная ошибка), и, наконец, назначает fd 2 (стандартная ошибка ) в то же место, что и fd 3 (стандартный вывод).
Стандартная ошибка теперь доступна в качестве стандартного вывода, а старый стандартный вывод сохраняется в стандартной ошибке. Это может быть излишним, но, надеюсь, даст больше подробностей о дескрипторах файлов Bash (для каждого процесса доступно девять).
источник
3>&-
закрыть запасной дескриптор, который вы создали из stdoutstderr
и другой, который имеет комбинациюstderr
иstdout
? Другими словами можноstderr
перейти к двум разным файлам одновременно?В Bash вы также можете перенаправить на подоболочку, используя подстановку процессов :
Для рассматриваемого случая:
источник
command 2> >(grep 'something' > grep.log)
grep.log содержит тот же вывод, что и ungrepped.log отcommand 2> ungrepped.log
2> >(stderr pipe >&2)
. В противном случае вывод «stderr pipe» будет проходить через «stdlog pipe».2> >(...)
работает, я пытался,2>&1 > >(...)
но не получилосьawk -f /new_lines.awk <in-content.txt > out-content.txt 2> >(tee new_lines.log 1>&2 )
В этом случае я хотел также увидеть, что выдает ошибки на моей консоли. Но STDOUT собирался в выходной файл. Таким образом, внутри вложенной оболочки вам нужно перенаправить этот STDOUT обратно в STDERR внутри скобок. Пока это работает, вывод STDOUT изtee
команды завершается в концеout-content.txt
файла. Это кажется мне неуместным.2>&1 1> >(dest pipe)
Объединяя лучшие из этих ответов, если вы делаете:
command 2> >(grep -v something 1>&2)
... тогда все stdout сохраняются как stdout, а все stderr сохраняются как stderr, но вы не увидите никаких строк в stderr, содержащих строку «что-то».
Это имеет уникальное преимущество, заключающееся в том, что они не меняют и не отбрасывают stdout и stderr, не соединяют их вместе и не используют какие-либо временные файлы.
источник
command 2> >(grep -v something)
(без1>&2
) то же самое?tar cfz my.tar.gz mydirectory/ 2> >(grep -v 'changed as we read it' 1>&2)
должно работать.Намного проще визуализировать вещи, если вы думаете о том, что на самом деле происходит с «перенаправлениями» и «каналами». Перенаправления и каналы в bash делают одно: изменяют место, на которое указывают дескрипторы файлов процессов 0, 1 и 2 (см. / Proc / [pid] / fd / *).
Когда труба или "|" оператор присутствует в командной строке, первое, что должно произойти, это то, что bash создает fifo и указывает FD 1 команды левой стороны на это fifo и указывает FD 0 команды правой стороны на то же самое fifo.
Затем операторы перенаправления для каждой стороны оцениваются слева направо , и текущие настройки используются всякий раз, когда происходит дублирование дескриптора. Это важно, потому что, поскольку канал был настроен первым, FD1 (левая сторона) и FD0 (правая сторона) уже изменились по сравнению с тем, чем они обычно могли быть, и любое их дублирование будет отражать этот факт.
Поэтому, когда вы печатаете что-то вроде следующего:
Вот что происходит по порядку:
Таким образом, весь вывод, который «команда» записывает в свой FD 2 (stderr), попадает в канал и читается «grep» с другой стороны. Весь вывод, который «команда» записывает в свой FD 1 (stdout), попадает в / dev / null.
Если вместо этого вы запускаете следующее:
Вот что происходит:
Итак, все stdout и stderr из «команды» идут в / dev / null. Ничто не идет в трубу, и, таким образом, "grep" закроется, не показывая ничего на экране.
Также обратите внимание, что перенаправления (файловые дескрипторы) могут быть только для чтения (<), только для записи (>) или для чтения-записи (<>).
Последнее замечание Записывает ли программа что-то в FD1 или FD2, полностью зависит от программиста. Хорошая практика программирования гласит, что сообщения об ошибках должны идти в FD 2, а нормальный вывод - в FD 1, но вы часто найдете неаккуратное программирование, которое смешивает два или иным образом игнорирует соглашение.
источник
Если вы используете Bash, то используйте:
http://www.gnu.org/software/bash/manual/bashref.html#Pipelines
источник
|&
равно2>&1
которому сочетает в себе stdout и stderr. Вопрос явно задан для вывода без stdout.>/dev/null |&
расширите до>/dev/null 2>&1 |
и означает, что inode stdout пуст по каналу, потому что никто (# 1 # 2, связанный с / dev / null inode) не связан с inode stdout (напримерls -R /tmp/* >/dev/null 2>&1 | grep i
, даст пустой, ноls -R /tmp/* 2>&1 >/dev/null | grep i
позволит # 2 который привязан к stdout inode будет труба).( echo out; echo err >&2 ) >/dev/null |& grep "."
дает никакого вывода (где мы хотим "ошибаться").man bash
говорит, что если | & используется… это сокращение от 2> & 1 |. Это неявное перенаправление стандартной ошибки на стандартный вывод выполняется после любых перенаправлений, указанных в команде. Итак, сначала мы перенаправляем FD1 команды на ноль, затем перенаправляем FD2 команды туда, куда указал FD1, т.е. NULL, поэтому grep FD0 не получает ввода. См. Stackoverflow.com/a/18342079/69663 для более подробного объяснения.Для тех, кто хочет перенаправить stdout и stderr навсегда в файлы, используйте grep для stderr, но оставляйте stdout для записи сообщений в tty:
источник
Это перенаправит команду command1 stderr на команду command2 stdin, оставив команду command1 stdout как есть.
Взято из ЛДП
источник
Я только что предложил решение для отправки
stdout
одной команде иstderr
другой, используя именованные каналы.Поехали.
Вероятно, это хорошая идея удалить именованные каналы позже.
источник
Вы можете использовать оболочку rc .
Сначала установите пакет (это менее 1 МБ).
Это пример того , как вы могли бы отказаться от стандартного вывода и стандартной ошибки трубы к Grep в
rc
:Вы можете сделать это, не выходя из Bash:
Как вы могли заметить, вы можете указать, какой дескриптор файла вы хотите передать, используя скобки после канала.
Стандартные файловые дескрипторы нумеруются так:
источник
Я пытаюсь следовать, найти это работать, а также,
источник