Teste de festança: o que "= ~" faz?

40
#!/bin/bash
INT=-5

if [[ "$INT" =~ ^-?[0-9]+$ ]]; then

echo "INT is an integer."

else

echo "INT is not an integer." >&2

exit 1

fi

O que o líder ~faz na expressão regular inicial?

Ragnarok
fonte
3
Não é uma regex, é um padrão de teste para determinar uma combinação regex ...
jasonwryan
5
Você leu o manual do bash? O que você acha incerto?
icarus 27/01
3
Pesquise na página do manual do bash = =
Jeff Schaller

Respostas:

46

Na ~verdade, é parte do operador =~que executa uma correspondência de expressão regular da string à sua esquerda e a expressão regular estendida à sua direita.

[[ "string" =~ pattern ]]

Observe que a string deve ser citada e que a expressão regular não deve ser citada.

Um operador semelhante é usado na linguagem de programação Perl.

As expressões regulares entendidas por bashsão as mesmas que o GNU grepentende com a -Eflag, ou seja, o conjunto estendido de expressões regulares.


Um pouco fora de tópico, mas é bom saber:

Ao fazer a correspondência com uma expressão regular que contém grupos de captura, a parte da sequência capturada por cada grupo está disponível na BASH_REMATCHmatriz. O zeroth / primeira entrada em Isto corresponde matriz para &no padrão de substituição sedde comando de substituição (ou $&em Perl), que é o bit da cadeia que corresponde ao padrão, enquanto as entradas no índice 1 e seguintes corresponde a \1, \2, etc. . em um sedpadrão de substituição (ou $1, $2etc, em Perl), isto é, os bits correspondentes por cada parêntese.

Exemplo:

string=$( date +%T )

if [[ "$string" =~ ^([0-9][0-9]):([0-9][0-9]):([0-9][0-9])$ ]]; then
  printf 'Got %s, %s and %s\n' \
    "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}"
fi

Isso pode gerar

Got 09, 19 and 14

se a hora atual for 09:19:14.

O REMATCHbit do BASH_REMATCHnome do array vem de "Correspondência de expressão regular", ou seja, "RE-Match".


Em bashshells não semelhantes a Bourne, pode-se também usar exprpara correspondência limitada de expressões regulares (usando apenas expressões regulares básicas).

Um pequeno exemplo:

$ string="hello 123 world"
$ expr "$string" : ".*[^0-9]\([0-9][0-9]*\)"
123
Kusalananda
fonte
2
É o mesmo que grep -Eentende apenas nos sistemas GNU e somente ao usar uma variável não citada como padrão [[ $var = $pattern ]](consulte [[ 'a b' =~ a\sb ]]vs p='a\sb'; [[ 'a b' =~ $p ]]). Observe também que a citação do shell afeta o significado dos operadores de ER e que alguns caracteres precisam ser citados para a tokenização do shell que pode afetar o processamento do RE. [[ '\' =~ [\/] ]]retorna falso. ksh93tem problemas ainda piores. Veja zsh(ou bash 3.1) para uma abordagem mais saudável, onde as cotações de shell e RE são claramente separadas. O [builtin de zshe yashtambém tem um =~operador.
Stéphane Chazelas
2
muito legal off-topic! 1 (
JJoao 27/17/17
@ StéphaneChazelas Como é "mais saudável" que ambas as partidas correspondam ao zsh ?: [[ "This is a fine mess." =~ T.........fin*es* ]]; [[ "This is a fine mess." =~ T.........fin\*es\* ]]. Ou que um citado *também corresponde? [[ "This is a fine mess." =~ "T.........fin*es*" ]].
sorontar 30/01
É mais saudável (IMO), pois é muito mais simples. As citações de shell e escape de RE são claramente separadas. Em [[ a =~ .* ]]ou [[ a =~ '.*' ]]ou [[ a =~ \.\* ]], o mesmo .*ER é passado para o =~operador. OTH, em bash, [[ '\' =~ [)] ]]retorna um erro, você saberia sem tentar se [[ '\' =~ [\)] ]]corresponde? Que tal [[ '\' =~ [\/] ]](acontece no ksh93). Que tal c='a-z'; [[ a =~ ["$c"] ]](comparar com o =operador)? Veja também: [[ '\' =~ [^]"."] ]]que retorna falso ... Note que você pode fazer shopt -s compat31em bashpara obter o zshcomportamento.
Stéphane Chazelas
zsh/ bash -o compat31'S comportamento para [[ a =~ '.*' ]]também é consistente com [ a '=~' '.*' ](por [implementações que suporte =~) ou expr a : '.*'. OTOH, não é consistente com [[ a = '*' ]]vs [[ a = * ]](mas, os globs fazem parte da linguagem shell, enquanto os REs não).
Stéphane Chazelas
4

Você deve ler as páginas do manual do bash, na [[ expression ]]seção

An additional binary operator, =~, is available, with the same precedence as == and !=. When it is used, the string to the right of the operator is considered an extended regular expression and matched accordingly (as in regex(3)).

Para encurtar a história, =~é um operador, assim como ==e !=. Não tem nada a ver com a regex real na string à sua direita.

Sokel
fonte
Você pode descobrir alguns exemplos demonstrando o uso =~na vida real ...?
George Vasiliou
11
@GeorgeVasiliou Eu o uso com bastante frequência em scripts que colocam a saída de um comando em uma variável. Em seguida, a variável é verificada para verificar se ela corresponde a algum padrão de sequência. Isso é útil, por exemplo, se você deseja executar alguma ação com base em alguma saída de erro desse comando.
Michael Martinez
@Sokel Para alguns, “RTFM” é mais fácil dizer do que fazer. ⋯ man [[ expresssion ]]e man [[não devolva nada. help [[retorna informações úteis - desde [[um comando bash interno - mas não diz se =~usa a sintaxe regex básica ou estendida. Text O texto que você citou é da página de manual do bash . Sei que você disse "leia as páginas de manual do bash", mas, a princípio, pensei que você pretendia ler as páginas de manual no bash. De qualquer forma, man bashretorna um arquivo enorme, com 4139 linhas (72 páginas). Pode ser pesquisado pressionando /▒▒▒, o que leva a uma expressão regular, cujo sabor - como =~- não é especificado.
Alex Quinn