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

12

Usando https://regex101.com/ , construí uma expressão regular para retornar a primeira ocorrência de um endereço IP em uma sequência.

RegExp:

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

RegExp incluindo delimitadores:

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

Com a seguinte cadeia de teste:

eu-west                       140.243.64.99 

Retorna uma correspondência completa de:

140.243.64.99

Não importa o que eu tente com âncoras, etc., o seguinte script bash não funcionará com a expressão regular gerada.

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
fonte
3
Isso me parece uma expressão regular do Perl. O Bash não suporta isso.
Kusalananda
1
O =~operador é discutido aqui no manual, onde está escrito bash usa "expressões regulares estendidas". Regexes estendidas são descritas na regex(7)página de manual e resumidas aqui .
Glenn Jackman

Respostas:

15

\dé uma maneira não-padrão de dizer "qualquer dígito". Eu acho que vem do Perl, e muitos outros idiomas e utilitários também suportam REs compatíveis com Perl (PCRE). (e, por exemplo, o GNU grep 2.27 no trecho Debian suporta o mesmo \wpara caracteres de palavras, mesmo no modo normal.)

O Bash não suporta \d, portanto, você precisa usar explicitamente [0-9]ou [[:digit:]]. O mesmo para o grupo de não captura (?:..), use apenas em (..)vez disso.

Isso deve imprimir match:

temp="eu-west                       140.243.64.99            "
regexp="([0-9]{1,3}\.)+([0-9]{1,3})"
[[ $temp =~ $regexp ]] && echo match
ilkkachu
fonte
2
Seu GNU grepsuporta \dsem -P?
Stéphane Chazelas
@ StéphaneChazelas, gritos, claro que não. Suporta \we \b, que aprendi com Perl, fiquei confuso.
22418 ilkkachu
não é realmente justo dizer \dou o PCRE é "fora do padrão". Eles são bastante padrão, apenas um padrão diferente das expressões regulares originais e das expressões regulares estendidas.
Daniel Farrell
1
@DanielFarrell, o padrão nesse caso é o que o POSIX especifica , e ele não conhece \d. Embora você esteja certo, os PCRE são bastante padrão ou menos definidos. A questão irritante é que o GNU grep (ou glibc) suporta alguns átomos do tipo PCRE, pelo menos \we \sao interpretar o ERE, e nesse contexto eles são muito fora do padrão. Meu fraseado pode vir em parte disso, e a coleta incorreta que \dfoi similarmente suportada pelo GNU.
ilkkachu
4

(:...)e \dsão operadores de expressão regular perl ou PCRE (como no GNU grep -P).

bashsuporta apenas expressões regulares estendidas como em grep -Eexceto que, para regexps passados ​​literalmente como em [[ text =~ regexp-here ]]oposição a como resultado de uma expansão não citada (como em [[ text =~ $var ]]ou [[ test =~ $(printf '%s\n' 'regexp-here') ]]), é limitado ao conjunto de recursos de expressão regular estendida POSIX.

Portanto, mesmo em sistemas onde grep -E '\d'funcionaria (os GNRE EREs já importaram algumas extensões dos regexps perl, como as \sfuturas versões podem ter \d), você teria que usar:

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

no bashpara que ele funcione ( [[ $text =~ \d ]]não).

Para um shell que suporte PCREs, você pode usar zsh:

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

O ksh93 também suporta sua própria implementação de expressões regulares do tipo perl (não totalmente compatíveis) como parte de sua correspondência de padrões. Lá, você usaria:

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

(observe o em =vez de =~. Você desejará usar variáveis ​​temporárias, pois elas são muito problemáticas quando não o fazem)

Stéphane Chazelas
fonte
1

O site regex101.com usa o PCRE (veja o canto superior esquerdo) como padrão e não possui suporte para a sintaxe regex "Estendida". Isso é "Expressões regulares compatíveis com Perl", que vêm (como é razoável esperar) do Perl.

O PCRE é suportado por algumas ferramentas (como grep -P) em algumas condições, mas o suporte ao regex bash dentro do [[…]]idioma é apenas para o regex estendido (como grep -E).

No regex estendido, o (?…)parêntese de não captura não existe e o \ d também está ausente. Você precisa usar simples (…)e [0-9]:

regexp="([0-9]{1,3}\.)+([0-9]{1,3})"
Isaac
fonte