LINUX.ORG.RU

Почему grep не фильтрует сообщения dd?

 , , , ,


0

1

Даю такую команду:

$ dd if=/dev/zero count=10000 bs=50000 of=/tmp/zero.bin | grep 10000
10000+0 записей получено
10000+0 записей отправлено
500000000 байт (500 MB, 477 MiB) скопирован, 5,00764 s, 99,8 MB/s
И ожидаю что третьей строки не будет видно, она же не попадает под выражение в grep.

Но третья строка все равно выводится в консоль.

Почему?

★★★★★
Ответ на: комментарий от TheAnonymous

Я вот не понимаю. Часто программы сообщают об ошибках в stderr, и чтобы ошибки увидеть, приходится делать 2>&1, и пока ты этого не сделаешь - что происходит не поймешь, потому что stderr не видно в консоли.

А тут stderr почему-то лезет в консоль.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

Я вот не понимаю. Часто программы сообщают об ошибках в stderr, и чтобы ошибки увидеть, приходится делать 2>&1, и пока ты этого не сделаешь - что происходит не поймешь, потому что stderr не видно в консоли.

А тут stderr почему-то лезет в консоль.

Смешались в кучу кони, люди. Проблема как раз в том, что часто ошибки и диагностические сообщения пишут в stdout у которого иногда слетает буферизация и всякие хитрые штуки вроде 2>&1 её выправляют.

А вот stderr не буферизованный, поэтому он всегда и должен лезть в консоль.

А с консольными утилитами в UNIX-like оно всегда так, кто в лес, а кто по дрова. Одни всё пишут в stdout, другие всё пихают в stderr, у третьих есть всё-таки разделение на stderr и stdout, стандартизации в этом плане адекватной походу нет.

EXL ★★★★★
()
Последнее исправление: EXL (всего исправлений: 1)
Ответ на: комментарий от EXL

Ога, проблема в том, что я не нашел ни одной документации, в которой бы внятно было написано, что такое stdout и stderr на самом деле на уровне байтиков и ОС и куда они выводятся.

Для меня это абстрактные «потоки» (я хз что под этим подразумевают разработчики), которые как-то разруливаются шеллом, и про которые мы знаем что в Си-шечке они являются указателями stdin (0)/stdout (1)/stderr (2) типа FILE* из stdio.h, а в Плюсиках cin/cout/cerr из iostream соответственно.

Но видимо и тебе и futuram-е известно нечто большее, можете здесь об этом рассказать (я не стебусь если что).

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от futurama

к чему это? для dd понятно, что при отсутствии of=… выброс пойдёт в stdout, соответственно всю диагностику пишем в stderr

Вот и я про то. Видимо, разгадка в том, что и в случае «>» и в случае «of=» утилита dd думает, что ее выхлоп попадает в stdout (хотя при of= это не так). И поэтому она всегда пишет сообщения в stderr.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

Но видимо и тебе и futuram-е известно нечто большее, можете здесь об этом рассказать (я не стебусь если что).

Так я тут как раз и рассказал то, что знаю и считаю важным:

stdout является буферизированным потоком, поэтому при некоторых обстоятельствах, таких как вывод чего-либо в быстром цикле и т. д. – сообщения могут запаздывать или сбрасываться внутрь консоли лишь после закрытия программы или после выхода из функций и пр. С этим связано много проблем при отладочном выводе printf()’ами в различных окружениях. Потому опытные программисты всегда выплёвывают отладку в fprintf(stderr, ...), чтобы избежать этих side-эффектов и сэкономить кучу времени.

stderr не является буферизированным потоком, поэтому вывод каких-либо сообщений в stderr моментально выведет их на консоль, даже в ущерб той производительности, которая обеспечивается буфером.

В популярных UNIX-like консольных программах, в т. ч. и входящих в Base System разных Linux-дистрибутивов нет чёткой градации и стандартов, когда использовать stderr, а когда – stdout, все делают так как того пожелают.

К примеру, я не понимаю почему GCC по gcc -v выплёвывает версию в stderr, вместо более логичного для этого stdout и пр. подобные примеры.

$ gcc -v | grep unknown
# Вывод в stderr.
# Хрен тебе! Ковыряйся с пайпами, вспоминай `1>&2` или `2>&1` или ещё как.

$ ld -v | grep unknown
# Вывод в stdout.
# Всё работает как надо.
EXL ★★★★★
()
Последнее исправление: EXL (всего исправлений: 1)
Ответ на: комментарий от futurama

А везде ли такое работает? Я вот помню, что раньше даже удобное command &> output.log не работало много где.

Но тейк-то тут больше в том, что нет толковой стандартизации в этих потоках и флажках тоже. Одни UNIX-программы из того же набора GCC как видишь ведут себя по-разному, хотя казалось бы.

EXL ★★★★★
()
Ответ на: комментарий от EXL

в bash

it is shorthand for 2>&1 |

Зачем стандартизация. Если тебе всегда нужны эти потоки вместе, то всегда юзай 2>&1

futurama ★★★★★
()
Последнее исправление: futurama (всего исправлений: 1)
Ответ на: комментарий от futurama

Да это понятно, но это не всегда удобно. Примеры из жизни: логинишься на экзотический сервак, роутер, Android-телефон и пр. технику где нет Bash’измов а юзается какой-нибудь Busybox. Соответственно комбинации &| и &> выходят из чата, а 2>&1 нормально лично у меня не запоминается. Мне приходится постоянно гуглить в такой ситуации, чтобы посмотреть как там правильно: 1>&2 или &2>1 или ещё как-то.

А был бы стандарт – все бы юзали корректно эти потоки и не парились. А в случае тех же несоответствий я бы мог завести баг-репорт в Issue репозитория GCC опираясь на строчки из подобного стандарта, чтобы он версию не в stderr плевал.

EXL ★★★★★
()
Ответ на: комментарий от EXL

Как бы их корректно не юзали, все-равно их (потоков) ДВА и в одной консоли ими придется манипулировать, а значит запоминать какой-то из вариантов перенаправления. Т.о. стандарт на то как и что и куда выводить не избавит тебя от гугления 2>&1

futurama ★★★★★
()
Ответ на: комментарий от EXL

К примеру, я не понимаю почему GCC по gcc -v выплёвывает версию в stderr, вместо более логичного для этого stdout и пр.

«Если ничего не помогает, прочтите, наконец, инструкцию.»

У ld -v является синонимом --version (ну, не совсем), у gcc — нет.

man gcc:

-v Print (on standard error output) the commands executed to run the stages of compilation. Also print the version number of the compiler driver program and of the preprocessor and the compiler proper.

man ld:

-v
--version
-V Display the version number for ld. The -V option also lists the supported emulations.

Чтобы вывести версию на stdout надо использовать стандартную гнушную опцию --version, которую понимает и gcc, и ld.

debugger ★★★★★
()
Последнее исправление: debugger (всего исправлений: 4)
Ответ на: комментарий от Xintrea

На уровне ядра есть только файловые дескрипторы и системные вызовы read()/write(). Номера 0,1,2 заданы однозначно на уровне библиотеки, типа соглашение/стандарт, возникший ещё до POSIX. Ядро эти дескрипторы никак не выделяет среди других.

Процессы типа initd/getty, с которых всё начинается, сами открывают нужные файл-устройство на эти дескрипторы, а остальные обычно просто наследуют от родителя и работают с тем, что дали. Потоки в Си-шечке (FILE *) просто надстройка, которая заканчиватется read()/write(). То, что при выводе терминал по умолчанию stdout — line buffered, а stderr — unbuffered, опять таки соглашение на уровне библиотеки (libc).

mky ★★★★★
()