Простой grep на что-нибудь год

Я знаю, что я делаю что-то сумасшедшее здесь, но чит-лист регулярных выражений, данный нам в моем классе Unix/Linux, подразумевал (по моим прочтениям), что это должно найти строки в текстовом файле, которые содержат годы (числа от 0000 до 9999):

grep \d{4} file.txt

Почему он ничего не находит вместо этого? Это использует bash, с тем же результатом, что и PuTTY в Windows и в Terminal на Mac. Я пробовал варианты с круглыми скобками и кавычками без эффекта. поиск [0-9][0-9][0-9][0-9] работает, но ничего не \d или же {4} кажется, работает как я ожидаю.

На связанной ноте, почему .\+ иметь эффект, который я ожидал бы .+ иметь, пока .+ просто "не работает"? (Я знаю, что это говорит grep искать что-то, но я не знаю, что.) А именно, кажется, это способ запросить "один или несколько символов здесь", а не "один символ, за которым следует знак плюс". (Это был правильный способ выполнить задание, и учитель мог объяснить, почему это так). И как можно искать "один символ, за которым следует знак плюс"?

3 ответа

Решение

Ваш шпаргалка может заявить, что \d{4} является действительным регулярным выражением, означающим "четыре цифры"; и это может заявить, что grep ищет файл для регулярного выражения. Взятые отдельно, оба эти утверждения верны. Но вместе взятые, они вводят в заблуждение, так как grep PATTERN FILE ожидает один вид регулярных выражений (POSIX "Базовые регулярные выражения", BRE), тогда как \d а также {4} являются нотациями из другого вида регулярных выражений (иногда называемых "Perl-совместимые регулярные выражения", PCRE, после языка программирования Perl).

Много версий grep поддерживать -P флаг, указывающий, что шаблон является PCRE, а не BRE; ты можешь попробовать:

grep -P '\d{4}' file.txt

(Обратите внимание на одинарные кавычки вокруг \d{4}, Это необходимо, потому что в противном случае Баш возьмет \d как своего рода сокращение для 'd' Таким образом, фактический образец передан grep будет d{4}, что означает "четыре d "вместо" четырех цифр ". Вы также можете написать grep -P \\d{4} file.txt, который решает ту же проблему по-другому.)


Отредактировано, чтобы добавить: Извините, я не смог охватить вторую часть вашего вопроса, о +, Итак, согласно соответствующим спецификациям, 1 это:

grep .+ file.txt

использования . означать "любой символ, кроме NUL" и + означать "фактический знак плюс". Так что это действительно должно напечатать строки file.txt которые содержат не начальный знак плюс; если вы видите другое поведение, то ваша оболочка и / или grep должен быть не соответствующим.

Кроме того, это:

grep .\+ file.txt

то же самое, что и выше, потому что соответствующая оболочка POSIX (такая как Bash) будет обрабатывать \+ как причудливый способ написания +, так grep увидим те же аргументы, что и раньше. (grep не будет возможности узнать, что вы напечатали .\+ скорее, чем .+.)

Наконец, это:

grep '.\+' file.txt

(где \ на самом деле передается grep) имеет неопределенное поведение: данное grep реализация может означать то же самое, что .+ или это может занять \+ быть специальным обозначением, означающим "один или несколько" (или что-то еще), или оно может выдавать сообщение об ошибке. Реализация GNU, как это бывает, принимает "одну или несколько" интерпретаций, но другие могут отличаться.

Примечания:

  1. А именно grep спецификации, а также спецификации BRE и ERE (которые grep Спек ссылки и ссылки). Также важна спецификация оболочки, так как именно оболочка определяет фактические аргументы, которые передаются grep,

По умолчанию grep использует разновидность POSIX regex, которая не включает \d, Чтобы использовать свое выражение, вам нужно переключиться на PCRE (arg -P)

grep -P \\d{4} file.txt 

Это вернет каждый экземпляр 4-значных строк в file.txt.

Если ваша версия grep бывает не поддерживать -P, будет работать следующее:

grep "\d\{4\}" file.txt

Что касается других ваших вопросов, используя тот же вид регулярных выражений, .+ будет соответствовать любому символу, сопровождаемому + знак. .\+ будет соответствовать одному или нескольким символам.

Другие вопросы по тегам