Однажды я заметил, что один из моих скриптов, сканирующих почтовые журналы, не выдал сообщение об одной записи, о наличии которой в журнале мне было известно (о ней меня оповестил другой скрипт). Работа скрипта начинается с использования
grep
для фильтрации записей, которые меня не интересуют:grep -hv 'a specific pattern' "$@" | exigrep '...' | [...]
Я, столкнувшись этим, чего только себе не напридумывал.
Может, я неправильно понимаю суть опции
-v
? А, может быть, команда exitgrep вытворяет что-то такое, о чём я и не подозреваю? В итоге я решил обработать файл с использованием одной только команды grep
, соединённой конвейером с командой less
, и, пользуясь less
, сразу открыл последние строки вывода, так как знал, что запись, которая в файле была, но о которой скрипт мне не сообщил, находилась где-то ближе к концу файла. Случилось то, чего я и ожидал. А именно, в определённый момент команда grep
просто остановилась. Я, в частности, увидел следующее:2020-04-13 16:07:06 H=(111iu.com) [223.165.241.9] [...]
2020-04-13 16:07:07 unexpected disconnection [...]
Binary file /var/log/exim4/mainlog matches
Ну конечно. Крайне полезные сведения. В процессе чтения того, что до этого команда считала текстовым файлом, она столкнулась с некими интересными символами (в строке с информацией о подписи DKIM) и решила, что файл, на самом деле, был бинарным, поэтому ей не нужно обрабатывать остаток файла, не нужно сообщать больше ни о чём, кроме того, что сообщено в последней строке.
(Этот случай отличается от поведения
grep
, когда программа полагает, вводимая в заблуждение багом файловой системы и собственной «интеллектуальностью», что некоторые текстовые файлы являются бинарными. То, что произошло в этот раз, объяснить гораздо проще.)Мне, в целом, нравятся GNU-версии стандартных Unix-утилит и их дополнительные возможности. Сюда, правда, не относится то поведение GNU grep, с которым я столкнулся. Особенно — когда результаты работы этой команды не выводятся в терминал. Я так думаю, что если программа начала выводить текстовые строки, то она должна и дальше их выводить, а не вести себя неким непредсказуемым образом.
Из этого всего я вынес ценный урок. Заключается он в том, что каждый раз, когда я обрабатываю текстовые файлы с помощью GNU grep (а в моих скриптах, в общем-то, я всегда обрабатываю текстовые файлы именно так), мне нужно явным образом указывать программе на то, что она должна воспринимать эти файлы именно как текстовые. Это, к сожалению, приведёт к «утяжелению» кода некоторых скриптов, так как порой я пользуюсь конвейерами, в которых используются несколько команд
grep
, применяемых для фильтрации и обработки текста. В результате мне нужно либо снабдить все используемые команды grep
опциями -a
, либо выяснить, какая переменная окружения вида LC_ позволит, с минимальным воздействием на систему, это отключить, либо — взяться за нечто такое, что можно сравнить со здоровенной кувалдой, использовав, как рекомендуется в справке по GNU grep, переменную LC_ALL=C
.
P.S. Описанная здесь проблема касается не только Linux, так как GNU grep используется не только на компьютерах, работающих под управлением Linux. Тут всё зависит от того, что именно устанавливают, и что именно попадает в переменную PATH
. Например, на FreeBSD-машине, к которой у меня есть доступ, GNU grep используется в виде /usr/bin/grep
.
Приходилось ли вам сталкиваться с неожиданными эффектами, возникающими при использовании Unix-команд?