Правильний регулярний вираз не працює в grep


13

У мене є цей регулярний вираз:

(?<=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 Compatible Regular Expression").

grepвиконує регулярні вирази POSIX. Це основні регулярні вирази (BRE) та розширені регулярні вирази (ERE, якщо grepвони використовуються з -Eопцією). Дивіться посібник для re_formatабо regexбудь-якого подібного посібника, до якого grepпосилається посібник у вашій системі, або стандартні тексти POSIX, до яких я тільки що посилався.

Якщо ви використовуєте GNU grep, ви могли б використовувати Perl-подібні регулярні вирази, якби ви використовували опцію grepGNU grep-specific -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не використовується аромат регулярного виразів з видом на відстань (за замовчуванням 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.