Forçando o Bash a usar o mecanismo Perl RegEx

11

Como você já deve saber, muitos dos recursos que os mecanismos modernos RegEx suportam (referência posterior, asserções de pesquisa etc.) não são suportados pelo mecanismo Bash RegEx. A seguir, é apresentado um script Bash simples que acabei de criar para tentar explicar qual é meu objetivo final:

#!/bin/bash

# Make sure exactly two arguments are passed.
if [ $# -lt 2 ]
then
    echo "Usage: match [string] [pattern]"
    return
fi

variable=${1}
pattern=${2}

if [[ ${variable} =~ ${pattern} ]]
then
    echo "true"
else
    echo "false"
fi

Por exemplo, algo como o seguinte comando retornará false:

. match.sh "catfish" "(?=catfish)fish"

enquanto a mesma expressão exata encontrará uma correspondência quando usada em um testador de regex Perl ou JavaScript.

As referências anteriores (por exemplo, (expr1) (expr2) [] \ 1 \ 2) também não serão correspondentes.

Acabei de concluir que meu problema só será resolvido ao forçar o bash a usar um mecanismo RegEx compatível com Perl. Isso é factível? Se sim, como eu realizaria o procedimento?

Fadi Hanna AL-Kass
fonte
5
Por que você não usa apenas perl em vez de bash para scripts? E por que essa pergunta está marcada com javascript?
Marco
Porque usar o Bash é uma obrigação na minha situação. E eu codifiquei acidentalmente o JavaScript. Tirei-:)
Fadi Hanna AL-Kass
2
Por que você não usar grepcom -Pou usando sed?
cuonglm
2
Mas você nunca explica a situação / problema que o levou a concluir que você deve fazer com que o shell faça algo que simplesmente não pode fazer. Existe uma maneira melhor.
27413 llua
Acho que as referências anteriores funcionam no bash 4.3.x (Ubuntu 14.04), mas não no bash 3.2x (OS X). Aqui está o meu comando de teste:re="([a-z])[0-9]\1"; [[ a1a =~ $re ]] && echo ${BASH_REMATCH[0]}
Digital Trauma

Respostas:

14

O Bash não suporta um método para você fazer isso no momento. Você tem as seguintes opções:

  1. Use Perl
  2. Usar grep [-P|--perl-regexp]
  3. Use a funcionalidade Bash para codificá-la

Eu acho que iria com o # 2 e tentaria usar greppara obter o que quero funcionalmente. Para referência remota, você pode fazer o seguinte com grep:

$ echo 'BEGIN `helloworld` END' | grep -oP '(?<=BEGIN `).*(?=` END)'
helloworld

-o, --only-matching       show only the part of a line matching PATTERN
-P, --perl-regexp         PATTERN is a Perl regular expression

(?=pattern)
    is a positive look-ahead assertion
(?!pattern)
    is a negative look-ahead assertion
(?<=pattern)
    is a positive look-behind assertion
(?<!pattern)
    is a negative look-behind assertion 

Referências

slm
fonte
Sinceramente, não sabia que grep tinha um [-P|--perl-regexp]token. Muito obrigado :-)
Fadi Hanna AL-Kass
@ FadiHannaAL-Kass - de nada. Obrigado pela pergunta.
Slm
2
Para a posteridade, apenas o GNU grep inclui a -Popção, e não é universal. O grep do FreeBSD é baseado no GNU, mas a documentação declara "Esta opção não é suportada no FreeBSD". No OSX, o grep também é baseado no GNU, mas a -Popção nem é mencionada na página do manual. E em outros sistemas unix cujo grep não é GNU, é improvável que você veja em -Pqualquer lugar. Se houver a possibilidade remota de que a portabilidade possa ser útil para você no futuro, recomendo evitar opções específicas do sistema operacional como esta.
ghoti
pcregreptambém é uma opção, se disponível.
Curinga
Deve-se notar que o zsh faz exatamente o que o OP solicitou, desde que a REMATCH_PCREopção esteja definida.
Tim Peoples
0

Pode-se usar pcregrep. Ele vem com o pacote pcreno CentOS e pcregrepno Ubuntu.

grep -P pode ter esse problema dependendo do sistema operacional / versão:

-P, --perl-regexp
              Interpret PATTERN as a Perl regular expression.  This is highly experimental and grep -P may warn of unimplemented features.
site80443
fonte