В прошлом посте я затронул тему с grep, так вот. У grep есть хороший ключик -q. При указании этого ключа, утилита прекращает свою работу, как только нашлась заданная подстрока. Это правильная оптимизация и ей нужно пользоваться, если нужно проверить наличие подстроки в файле.

Давай попрактикуемся и с помощью strace посмотрим, как чо там в кишках происходит. Создаем большой файл и забиваем его рандомными данными:

head -c 1G /dev/urandom > /tmp/large

Если head не понимает буковку G в размере, то указываем явный размер файла: -c 1073741824

.

Так, файл размером 1G готов /tmp/large, дальше запускаем:

strace -P /tmp/large -ye read grep -q 's' /tmp/large

Ключи: -P = путь до файла -y = выводит имя пути до файла -e = команда которую дебажим

Через секунду, на выходе получаем нечто подобное:

read(3</tmp/large>, "v\310*A\307\16\324m&V8H\202\326\177\244\3059\27}00_\274\300<\245.X\27\310`"..., 98304) = 98304
+++ exited with 0 +++
Роман Шубин
Роман Шубин
CEO & CTO, Главред в «Цифровой улей»
Задать вопрос
То есть с опцией -q, grep не стал читать полностью весь гигабайтный файл, а сделал лишь один системный вызов read(3</tmp/large) и тут же завершил работу. Искомая строка нашлась, вернулся статус 0. Про статусы выхода я писал в этом посте.

Делаем то же самое без strace и проверяем статус выхода, все ли идентично:

grep -q 's' /tmp/large
echo $?

На выходе у нас будет 0. Ок, эксперимент завершился успехом. Некоторые версии grep могут возвращать истину если ошибка произошла, не связанная с поиском. Этот момент нужно учитывать. Про такие случаи хорошо написано здесь.

Если коротко, некоторые версии grep с ключом -q могут вернуть статус выхода 2. Так что на разных системах работать может по-разному. Если в своих скриптах проверяешь эти статусы, логика может сломаться, будь аккуратнее с этим.

Еще нюанс, можно добиться такого же поведения grep, но без ключа -q. Это сработает, если вывод перенаправлен в /dev/null. Ну это и логично, нам не нужен никакой вывод на экран и нет никакого смысла продолжать читать огромный файл если подстрока уже найдена.

strace -P /tmp/large -ye read grep 's' /tmp/large > /dev/null

Утилита grep (без ключа -q) также сделает один системный вызов read и прекратит свою работу, как только найдет первое совпадение.

Вроде несложно рассказал, по крайней мере попытался. Ладно, рад всех видеть, побежал дальше работу работать, сумасшедший какой-то день. Пока пока!