В прошлом посте я затронул тему с 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 +++



То есть с опцией -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 и прекратит свою работу, как только найдет первое совпадение.



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



tags: #linux #bash #debug



💩 @bashdays