Правильное регулярное выражение не работает в grep


13

У меня есть это регулярное выражение:

(?<=prefix).*$

который возвращает любой символ, следующий за строкой «prefix», и отлично работает на любых онлайн-движках регулярных выражений (например, https://regex101.com ). Проблема в том, что я использую это регулярное выражение в bash:

grep '(?<=prefix).*$' <<< prefixSTRING

это ничего не соответствует. Почему это регулярное выражение не работает с grep?


11
Это действительно подчеркивает, почему regex101 нуждается в селекторе ароматов POSIX, как это делается для JS, Perl / PHP и Python. Я не могу сосчитать, сколько раз я желал этого.
Джаред Смит


Кроме того, .*$сопоставляется любая строка до конца строки (или конца строки), а не только один символ.
ilkkachu

Ответы:


38

Кажется, вы определили правильное регулярное выражение, но не установили достаточные флаги в командной строке, grepчтобы понять его. Потому что по умолчанию grepподдерживает BRE, а с -Eфлагом - ERE. То, что у вас есть (прогноз), доступно только в виде регулярного выражения PCRE, которое поддерживается только в GNU grepс его -Pфлагом.

Предполагая, что вам нужно извлечь только совпадающую строку после prefixтого, как вам нужно добавить дополнительный флаг, -oчтобы сообщить, grepчто печатать только соответствующую часть как

grep -oP '(?<=prefix).*$' <<< prefixSTRING

Существует также версия, grepкоторая поддерживает библиотеки PCRE по умолчанию - pcregrepв которой вы можете просто сделать

pcregrep -o '(?<=prefix).*$' <<< prefixSTRING

Подробное объяснение различных разновидностей регулярных выражений объясняется в этом замечательном ответе Джайлса и инструментах, которые реализуют каждый из них.


38

Регулярные выражения бывают разных вкусов. То, что вы показываете, представляет собой Perl-подобное регулярное выражение (PCRE, «Perl-совместимое регулярное выражение»).

grepделает POSIX регулярные выражения. Это базовые регулярные выражения (BRE) и расширенные регулярные выражения (ERE, если grepиспользуется с -Eопцией). См. Руководство re_formatили regexаналогичное руководство, на которое grepссылается ваше руководство в вашей системе, или стандартные тексты POSIX, на которые я только что ссылался.

Если вы используете GNU grep, вы сможете использовать Perl-подобные регулярные выражения, если используете опцию, специфичную для grepGNU .grep-P

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

Обратите внимание, что оба -Pи -oявляются нестандартными расширениями спецификации POSIXgrep .

Если вы не используете GNU grep, sedвместо этого вы можете использовать бит между строкой prefixи концом строки:

sed -n 's/.*prefix\(.*\)/\1/p' file

Для этого нужно только напечатать строки, которым sedудается применить данную замену. Подстановка заменит всю строку, которая соответствует выражению (которое является BRE), тем фрагментом, который следует за строкой prefix.

Обратите внимание, что если prefixв строке есть несколько экземпляров , sedвариант вернет строку после последней , а grepвариант GNU вернет строку после первой (которая будет включать другие экземпляры prefix).

sedРешение будет переноситься на всех Unix-подобные системы.


6

Как указывалось в других ответах, grepне используется выражение regex с lookbehinds (по умолчанию с GNU grepили не используется с другими версиями).

Если вы не можете использовать GNU grepили pcregrep, вы можете использовать его, perlесли он у вас есть.

Эквивалент командной строки с perl:

perl -ne 'print if /(?<=prefix).*$/' <<< prefixSTRING

Вы помещаете желаемое регулярное выражение между слешами. Так как вы используете Perl, в нем используется регулярное выражение Perl .


или print "$&\n" if ...если они хотят вывести только часть послеprefix
ilkkachu
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.