Какова природа команды grep?

Какова природа команды grep?

Я хотел выполнить grep всех .txt-файлов, используя подстановочный символ '*'.
Я попробовал эту команду (а также без кавычек " "), но не получилось.

ls | grep "*.txt"

Интересно то, что если я добавлю в команду grep другой символ, соответствующий файлу .txt в каталоге, то это сработает

>>ls | grep s*.txt
sample.txt

Я знаю, что это ls *.txtсработает, но я был немного поражен природой команды grep. Может ли кто-нибудь помочь мне, почему это происходит?

Может это из-за того, что grep использует регулярные выражения? Помогите, пожалуйста.

решение1

В регулярных выражениях *означает «любое количество предыдущих элементов», а не «любое количество любых символов», как в шаблонах оболочки. И .означает «любой отдельный символ». Таким образом, чтобы найти «что угодно, за которым следует литерал .txt», вы бы использовали .*\.txt. Или просто \.txt, так как обычно сопоставления регулярных выражений ищут совпадение в любом месте строки. Затем снова \.txtбудет соответствовать имени файла, например foo.txtgz, так как .txtне обязательно должно быть в конце. Вам нужно будет \.txt$заблокировать шаблон в конце строки.

Регулярное выражение *.txtлибо бессмысленно, либо ошибочно, либо ищет буквальную звездочку, в зависимости от реализации и от того, используете ли вы базовые регулярные выражения ( grep) или расширенные регулярные выражения ( grep -E). Лучше не использовать его.

С другой стороны, s*.txtбудет искать "любое количество букв s, затем любой одиночный символ, затем литерал txt". Это более допустимое регулярное выражение, но... все еще не соответствует sample.txt.

Вместо этого, что происходит во второй команде, так это то, что поскольку s*.txtне заключен в кавычки, оболочка расширяет s*.txtдо того, как grepувидит его. Если единственным соответствующим файлом является sample.txt, то grepон ищет его в выводе ls. (Если бы было несколько соответствующих имен файлов, первое было бы принято в качестве шаблона, а остальные — как имена файлов для grepчтения. В этом случае он бы проигнорировал ввод из конвейера.)


Но, lsтакже можно взять список файлов, так что, хотя вы могли бы использовать

ls | grep '\.txt'

чтобы получить любой .txtфайл, наверное, было бы проще просто использовать

ls *.txt 

вместо.

решение2

Отчасти это связано с тем, что grepон использует регулярные выражения (на самом деле, именно это и reозначает в названии — это сокращение отгглобальныйррегулярныйевыражениепринт).

Подстановочный *знак в регулярных выражениях отличается от *подстановочного знака в подстановке оболочки.

В регулярных выражениях *означает «ноль или более ранее определенного объекта». Однако .,такжеподстановочный знак, означающий «один символ».

В shell-глобах *означает «ноль или более символов». .Это вовсе не подстановочный знак.

При поиске grepпо шаблону "*.txt"вы ищете ноль или более символов, за которыми следует еще один символ, а затем буквальная строка txt.

Когда вы grepдля шаблона "s*.txt"m you are looking for a literals , followed by zero or mores s, followed by any character, followed by the literal stringtxt`.

Вот почему в регулярных выражениях вы часто найдете .*, что означает «один любой символ, за которым следует ноль или более любых символов». Регулярное выражение для «буквально любая комбинация символов, кроме нуля символов».

Когда вы ls *.txtсообщаете оболочке: «Найдите все имена файлов, соответствующие шаблону glob *.txt, перечислите их здесь и укажите их в качестве аргументов команды» ls.

решение3

обратите внимание, что grep ищет файлсодержаниев то время как первый аргумент - это ШАБЛОН поиска, а другие аргументы интерпретируются как ФАЙЛЫ для поиска

это станет более понятным для вас, если использовать grep -H -oфлаги или поместить их grepвнутрь скрипта и запустить его, bash -x scriptчтобы увидеть, как расширяются подстановки оболочки перед передачей в качестве аргументов

Связанный контент