Простой 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, как это бывает, принимает "одну или несколько" интерпретаций, но другие могут отличаться.
Примечания:
- А именно
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
Что касается других ваших вопросов, используя тот же вид регулярных выражений, .+
будет соответствовать любому символу, сопровождаемому +
знак. .\+
будет соответствовать одному или нескольким символам.