Como escrever o literal regexp na expressão de correspondência?

2

Esta questão é sobre a maneira correta de escrever expressões regulares literais em uma expressão de correspondência no bash.

No zsh, a correspondência abaixo é bem-sucedida, como eu esperava:

% [[ ' 123 ' =~ '^ [0-9]+ $' ]]; echo $?
0

Não é assim no bash:

$ [[ ' 123 ' =~ '^ [0-9]+ $' ]]; echo $?
1

Eu sei que esta partida é bem sucedida em bash

$ ( regexp='^ [0-9]+ $'; [[ ' 123 ' =~ $regexp ]]; echo $? )
0

... mas requer a atribuição da expressão regular a uma variável intermediária.

Minha pergunta é: como alguém escreve uma expressão regular arbitrária literal em uma expressão de correspondência sob o bash?

    
por kjo 21.11.2018 / 21:09

2 respostas

6

É melhor colocá-lo em uma variável, como recomendado pelo manual de referência do Bash 3.2 .4.2 Construções condicionais :

Storing the regular expression in a shell variable is often a useful way to avoid problems with quoting characters that are special to the shell. It is sometimes difficult to specify a regular expression literally without using quotes, or to keep track of the quoting used by regular expressions while paying attention to the shell’s quote removal. Using a shell variable to store the pattern decreases these problems.

No entanto, para escrevê-lo diretamente dentro do bash extended test, você precisa remover as aspas e escapar dos espaços:

$ [[ ' 123 ' =~ ^\ [0-9]+\ $ ]]; echo $?
0
    
por 21.11.2018 / 21:21
2

No bash, a resposta canônica é: usar um var

$ reg='^ [0-9]+ $'
$ [[ ' 123 ' =~ $reg ]]; echo $?

Isso funciona para espaços, barras invertidas e muitas outras coisas:

$ reg='^ 12 $'
$ [[ ' 12 ' =~ $reg ]]; echo $?
0

Se você quiser escrevê-lo como um literal , precisará reproduzir ( cuidadosamente ) com aspas. Você precisa citar as partes que precisam ser literais e deixar as partes que devem ser interpretadas como um regex não citado. O espaço precisa de cotação. Aqui usando backslah:

$ [[ ' 123 ' =~ ^\ [0-9]+\ $ ]]; echo $?
0

E aqui usando aspas duplas:

$ [[ ' 123 ' =~ ^" "[0-9]+" "$ ]]; echo $?

Mas essa "citação" fica muito confusa com coisas como uma barra invertida:

$ [[ ' 12 ' =~ ^" "[0-9]+"\"[0-9]+" "$ ]]; echo $?
0

Mais simples, mais seguro:

$ reg='^ [0-9]+\[0-9]+ $'
$ [[ ' 12 ' =~ $reg ]]; echo $?
0

E, não, você não precisa de um subshell para fazer isso (o parêntese na sua pergunta).

$ reg='^ [0-9]+\[0-9]+ $'; [[ ' 12 ' =~ $reg ]]; echo $?

Sim, isso pode parecer irritante. E, sim, o comando que você apresentou funciona em zsh:

$ [[ ' 123 ' =~ '^ [0-9]+ $' ]]; echo $?
0

Mas a citação é sempre um problema (em qualquer shell), o que deve acontecer com a barra invertida?:

% [[ ' 12 ' =~ ' 12 ' ]]; echo $?
zsh: failed to compile regex: Invalid back reference
1


% [[ ' 12 ' =~ '^ [0-9]+\3 $' ]]; echo $?
0

Duplique! Não é exatamente: literal .

    
por 21.11.2018 / 21:23