Команда find с опцией -regex и использованием символа каретки проявляет неожиданное поведение.

Вопрос или проблема

Я хотел бы выполнить команду find и получить некоторые файлы/каталоги в директории рабочего стола, используя опцию regex команды с символом кареткой ^

Как вы знаете, каретка ^ соответствует началу строки, и я хотел бы получить все файлы/каталоги, начинающиеся с буквы t; я использовал следующую команду find . -regex "^./t", но, как оказалось, она будет соответствовать только файлу/папке, имя которого — простое t!

Я знаю, что regex будет соответствовать всему пути, а не только имени файла. Но почему все эти файлы не совпадают, если они начинаются с ./t.

./tcpdump.txt
./t.txt
./test.sh
./trade.txt
./torbrowser.desktop
./token.txt

PS: Этот regex сработал для меня, ^./t.*, но я все еще не понимаю поведение каретки в оригинальной команде

Опция -regex ожидает шаблон, который соответствует всему файлу. См. man find:

-regex pattern

Имя файла соответствует шаблону регулярного выражения. Это совпадение для всего пути, а не поиск. Например, для совпадения файла с именем ./fubar3 вы можете использовать регулярное выражение ‘.*bar.’ или ‘.*b.*3′, но не ‘f.*r3′. Регулярные выражения, которые понимает команда find, по умолчанию являются регулярными выражениями Emacs, но это можно изменить с помощью опции -regextype.

Каретка бессмысленна в этом контексте, поскольку, как объяснялось выше, -regex должен соответствовать всему, так что по сути ^ и $ подразумеваются.

Вы указали ^./t, что означает “ищите любой символ” (помните, что . означает “любой символ” в регулярных выражениях, это не значит буквальный .) за которым следует /, а затем одна буква t и больше ничего.

Что вам нужно здесь, так это оператор -name, который принимает глобальные шаблоны, а не регулярные выражения, и соответствует только имени файла, а не всему пути. Поэтому, чтобы найти все файлы/каталоги, имена которых начинаются с t, используйте:

find . -name "t*"

Глобальный шаблон t* означает “t, за которым следует 0 или более символов”. Если вы действительно хотите сделать это с помощью -regex, хотя это только усложняет задачу, вам нужно указать, что вы позволяете любому символу следовать за t, например, так:

find . -regex '.*/t.*'

Это регулярное выражение означает “совпадать с максимально возможным количеством символов (включая 0), пока не встретится последний /, а затем t, за которым следуют любые другие символы.

Тот факт, что регулярное выражение всегда соответствует всему пути, означает, что каретка и доллар избыточны: должен совпадать весь путь, а не только его подстрока. Или вы всегда можете представить, что регулярное выражение начинается с каретки и заканчивается долларом, даже если вы их не вводите.

Ответ или решение

Команда find с опцией -regex может вводить в заблуждение, особенно если вы пытаетесь использовать символ каретки ^ для поиска файлов, начинающихся на определённую букву. Давайте разберёмся, почему ваш исходный запрос find . -regex "^./t" не работает так, как вы ожидали.

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

Когда вы используете ^./t, ваше регулярное выражение фактически говорит: «совпадение начинается с ./t и ничем не продолжается». Это означает, что будет найден только файл или папка с именем t в каталоге, а не файлы, начинающиеся с t, как, например, test.sh или token.txt, так как они имеют дополнительные символы после t.

Ваша гипотеза о том, что символ каретки ^ совпадает только с началом строки, верна, и в контексте -regex это действительно не нужно. Символы ^ и $ подразумеваются: регулярное выражение должно соответствовать всему пути к файлу.

Если вы хотите найти все файлы и каталоги, начинающиеся с буквы t, рекомендуется использовать оператор -name, который принимает глобальные шаблоны (globs) и учитывает только имя файла, а не весь путь. Например, команда:

find . -name "t*"

выполнит вашу задачу, находя все элементы, имена которых начинаются с буквы t. Здесь t* означает «начинается с t и за ним может следовать 0 или более символов».

Если вы всё же хотите использовать регулярные выражения, вам нужно будет сделать следующее:

find . -regex '.*/t.*'

Это выражение «согласовывает с любым количеством символов (включая 0) до последнего /, а затем ищет t и любые символы после этого».

Таким образом, чтобы избежать путаницы:

  • Используйте -name для простых задач поиска по имени файла.
  • Если используете -regex, не забудьте учитывать, что выражение должно совпадать с полным путем и это может делать использование ^ и $ излишним.

Надеюсь, это поможет прояснить поведение команды find с опцией -regex и сделает ваш поиск более эффективным.

Оцените материал
Добавить комментарий

Капча загружается...