A validação de regex do subdomínio Bash nunca corresponde

0

Estou tentando verificar se um subdomínio inserido por um usuário é válido, mas, seja lá o que for que eu passe, ele nunca é válido. Eu sei que o regex é ok, então o problema é minha lógica "se", no entanto eu sou novo em shell / bash

#!/bin/bash
#

echo Enter the subdomain\'s name to configure.
read SUBDOMAIN

if [[ ! $SUBDOMAIN =~ [A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])? ]]; then
    echo "$SUBDOMAIN is not a valid domain"
fi

Exemplos:
Seriam aceitos (nomes regulares de subdomínio): teste
Não será aceito (nome do subdomínio inválido): -
Não seria aceito (nome do subdomínio inválido): (Empty)
Não será aceito (nome do subdomínio inválido): # $ ?? & @ # &? $ ## $

Eu preferiria usar o shell, mas os parênteses no regex fazem o script lançar um erro.

Não tenho certeza se isso pode ser feito com o grep, mas nunca entendi como usar o grep e isso sempre me confundiu.

    
por NaturalBornCamper 30.04.2018 / 17:47

2 respostas

2

Se você estiver tentando corresponder "alfanumérico" seguido por "alfanumérico ou traço", garantindo que não haja um traço no final, de modo que haja um total de 1.62 caracteres, esse RE funcionará para você

^[[:alnum:]](([[:alnum:]]|-){0,61}[[:alnum:]])?$

Isso se liga ao início e ao final da string, então o RE deve corresponder à string em sua totalidade.

  • Início da linha ^
  • Um único alfanumérico, qualquer caso [[:alnum:]]
  • Um bloco opcional (entre colchetes ( ... ) e terminado com ? )
    • [[:alnum:]] ou um traço - , repetido 0.60 vezes
    • [[:alnum:]]
  • Fim da linha $

Como foi recomendado nos comentários desta resposta, devo salientar que o intervalo [[:alnum:]] é afetado pela localidade atual. Se você quiser garantir que ele corresponda apenas a "ASCII" A-Z, a-z e 0-9, é necessário garantir que ele esteja sendo executado com LANG=C . Caso contrário, você pode descobrir que caracteres adicionais são aceitos, como á é ø ß e outros.

    
por 30.04.2018 / 18:16
0

Resumo:

Intervalo: você precisa alterar o LANG em um subnível: (LANG=C; echo "${a//[^a-zA-Z]}")

Lista: caracteres explícitos: r1=$(printf '%s' {a..z} {A..Z} {0-9})
Construa regex em partes: r2="[$r1]"; r3="[$r1-]"; reg="^$r2($r3{0,61}$r2)?$"

Use a regex final como: if [[ ! $SUBDOMAIN =~ $reg ]]; then

intervalos

A correspondência do intervalo a-z ou A-Z oculta várias surpresas.

Uma regex simples (ou glob) como [a-z] corresponderá a muitos outros caracteres:

$ a='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
$ echo "${a//[^a-z]}"
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY

Observe que apenas o Z foi removido. A localidade pode mudar isso:

$ LANG=C
$ echo "${a//[^a-z]}"
abcdefghijklmnopqrstuvwxyz

É ainda pior se o intervalo [[:alnum:]] for usado:

$ LANG=en_US.utf8
$ a='aáàäåbcdeéèëfAÁÀÄBßCRS§TUVWXYZ'
$ echo "${a//[^a-z]}      ${a//[[:alnum:]]}"
aáàäåbcdeéèëfAÁÀÄBßCRSTUVWXY      aáàäåbcdeéèëfAÁÀÄBßCRSTUVWXYZ

O primeiro intervalo removido §Z , alnum removeu apenas o § .
Com LANG = C, fica melhor:

$ LANG=C
$ a='aáàäåbcdeéèëfAÁÀÄBßCRS§TUVWXYZ'
$ echo "${a//[^a-z]}      ${a//[^[:alnum:]]}"
abcdef      áàäåéèëÁÀÄߧ

Um intervalo para incluir o Z pode funcionar melhor.

$ LANG=en_US.utf8
$ a='ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_'abcdefghijklmnopqrstuvwxyz'
$ echo "${a//[^a-Z]}"
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz

Mas ainda incluirá muitos outros caracteres UNICODE.

$ LANG=en_US.utf8
$ a='AÁÀÄBßCRSTUVWXYZ[]^_'aáàäåbcdeéèëf-ěžíňř'
$ echo "${a//[^a-Z]}"
AÁÀÄBßCRSTUVWXYZaáàäåbcdeéèëfěíňř

E usando a configuração da linguagem C, basta alterar o problema para:

$ LANG=C
$ a='AÁÀÄBßCRSTUVWXYZ[]^_'aáàäåbcdeéèëfxyz-ěžíňř'
$ echo "${a//[^A-z]}     ${a//[^[:alnum:]]}"
ABCRSTUVWXYZ[]^_'abcdefxyz     ABCRSTUVWXYZabcdefxyz

Subshell

Para usar a opção LANG=C , é comum precisar de um sub-shell para evitar alterar o valor de LANG no shell em execução:

$ (LANG=C; echo "${a//[^a-zA-Z]}")
ABCRSTUVWXYZabcdefxyz

Lista

Uma lista explícita de caracteres evitará tanto a questão do agrupamento quanto a necessidade de alterar a variável LANG (expansões de chaves usam apenas o local padrão C):

$ r1=$(printf '%s' {a..z} {A..Z})
$ echo "$r1"
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
$ a='AÁÀÄBßCRSTUVWXYZ[]^_'aáàäåbcdeéèëfxyz-ěžíňř'
$ echo "${a//[^"$r1"]}"
ABCRSTUVWXYZabcdefxyz

Para A-Z, a-z e 0-9, use:

r1=$(printf '%s' {A..Z} {a..z} {0..9})

Em seguida, crie os dois tipos de valores de expressão regular necessários:

r2="[$r1]"
r3="[$r1-]"

E o regex completo será:

reg="^$r2($r3{0,61}$r2)?$"

use como (é melhor que o regex esteja dentro de uma variável):

if [[ ! $SUBDOMAIN =~ $reg ]]; then
    
por 01.05.2018 / 06:10