Bash = ~ regex и https://regex101.com/

12

Используя https://regex101.com/, я построил регулярное выражение, которое возвращает первое вхождение IP-адреса в строку.

RegExp:

(?:\d{1,3}\.)+(?:\d{1,3})

RegExp, включая разделители:

/(?:\d{1,3}\.)+(?:\d{1,3})/

Со следующей тестовой строкой:

eu-west                       140.243.64.99 

Возвращает полное совпадение:

140.243.64.99

Независимо от того, что я пробую с якорями и т.д., следующий скрипт bash не будет работать с сгенерированным регулярным выражением.

temp="eu-west                       140.243.64.99            "
regexp="(?:\d{1,3}\.)+(?:\d{1,3})"
if [[ $temp =~ $regexp ]]; then
  echo "found a match"
else
  echo "No IP address returned"
fi
rjm61
источник
3
Это похоже на регулярное выражение Perl для меня. Баш не поддерживает это.
Кусалананда
1
=~Оператор обсуждается здесь в руководстве , где это написано Баш использует «расширенные регулярные выражения». Расширенные регулярные выражения описаны на regex(7)странице руководства и кратко изложены здесь .
Гленн Джекман

Ответы:

15

\dэто нестандартный способ сказать «любая цифра». Я думаю, что это происходит от Perl, и многие другие языки и утилиты также поддерживают Perl-совместимые RE (PCRE). (и, например, GNU grep 2.27 в Debian stretch поддерживает подобное \wдля символов слова даже в обычном режиме.)

Bash не поддерживает \d, так что вам нужно явно использовать [0-9]или [[:digit:]]. То же самое для группы без захвата (?:..), используйте только (..)вместо этого.

Это должно напечатать match:

temp="eu-west                       140.243.64.99            "
regexp="([0-9]{1,3}\.)+([0-9]{1,3})"
[[ $temp =~ $regexp ]] && echo match
ilkkachu
источник
2
Ваш GNU grepподдерживает \dбез -P?
Стефан Шазелас
@ StéphaneChazelas, конечно, нет. Он поддерживает \wи \b, что я узнал от Perl, поэтому я запутался.
ilkkachu
это не совсем справедливо, \dили PCRE являются «нестандартными». Они довольно стандартны, просто отличаются от оригинальных регулярных выражений и расширенных регулярных выражений.
Дэниел Фаррелл,
1
@DanielFarrell, стандарт в этом случае - это то, что определяет POSIX , и о котором он не знает \d. Хотя вы правы в том, что PCRE довольно стандартны или наименее четко определены. Раздражает проблема в том , что GNU Grep (или Glibc) поддерживает некоторые PCRE-атомов, по крайней мере , \wи \sпри интерпретации ERE, и в этом контексте они очень являются нестандартными. Моя формулировка вполне может быть отчасти из-за этого и из-за неправильного выбора, который \dбыл аналогично поддержан GNU.
ilkkachu
4

(:...)и \dявляются операторами регулярного выражения perl или PCRE (как в GNU grep -P).

bashподдерживает только расширенные регулярные выражения, как, за grep -Eисключением того, что для регулярных выражений , переданных буквально, в [[ text =~ regexp-here ]]отличие от результата раскрытия без кавычек (как в [[ text =~ $var ]]или [[ test =~ $(printf '%s\n' 'regexp-here') ]]), он ограничен расширенным набором функций регулярного выражения POSIX.

Таким образом, даже в системах, где grep -E '\d'это сработает (GNU ERE уже импортировали некоторые расширения из регулярных выражений perl, как, например, в \sбудущих версиях \d), вам придется использовать:

regexp='\d'
[[ $text =~ $regexp ]]

в bashдля его работы ( [[ $text =~ \d ]]не будет).

Для оболочки, которая поддерживает PCRE, вы можете использовать zshвместо этого:

set -o rematchpcre
[[ $text =~ '(?:\d{1,3}\.)+(?:\d{1,3})' ]]

ksh93 также поддерживает собственную реализацию perl-подобных регулярных выражений (не полностью совместимых) как часть сопоставления с образцом. Там вы бы использовали:

regexp='~(P)(?:\d{1,3}\.)+(?:\d{1,3})'
[[ $text = $regexp ]]

(обратите внимание на =вместо =~. Вы можете использовать временные переменные, поскольку он очень глючит, когда вы этого не делаете)

Стефан Шазелас
источник
1

На сайте regex101.com по умолчанию используется PCRE (смотрите в верхнем левом углу), и на нем отсутствует поддержка расширенного синтаксиса регулярных выражений. Это "Perl-совместимые регулярные выражения", которые происходят (как и следовало ожидать) от Perl.

PCRE поддерживается некоторыми инструментами (например grep -P) в некоторых условиях, но поддержка bash regex внутри [[…]]идиомы предназначена только для расширенного регулярного выражения (например grep -E).

В расширенном регулярном выражении неперехватывающая (?…)скобка не существует, и \ d также отсутствует. Вам нужно использовать простые (…)и [0-9]:

regexp="([0-9]{1,3}\.)+([0-9]{1,3})"
Исаак
источник