Expressão regular que corresponde aos códigos de idioma no bash

0

Existe uma questão semelhante em stackoverflow , mas não funciona com bash.

O que é necessário para que funcione com o bash, para usar scripts / variáveis?

Estou falando dos códigos ISO 639-1 ou ISO 639-2.

Meu bash é o GNU 4.3.

Exemplo:

root@box ~/test2 # ls
eng  en-US  por pt-BR

O regex nessas páginas falha:

root@box ~/test2 # ls | grep ^[a-z]{2}-[A-Z]{2}$
root@box ~/test2 # ls | grep ^[A-Za-z]{1,8}(-[A-Za-z0-9]{1,8})*$
-bash: syntax error near unexpected token '('
root@box ~/test2 # ls | grep ^[a-z]{2}(-[A-Z]{2})*
-bash: syntax error near unexpected token '('
root@box ~/test2 # ls | grep "^[a-z]{2}(-[A-Z]{2})*"
    
por Freedo 15.01.2018 / 09:50

3 respostas

4

{n} sem barras invertidas faz parte das expressões regulares estendidas, portanto você precisa da -E flag para grep. Além disso, você deseja citar o regex, pois, como você viu, os parênteses e chaves têm um significado especial para o shell.

$ ls
eng  en-US  por  pt-BR

$ printf "%s\n" * | grep -E '^[a-z]{2}-[A-Z]{2}$'
en-US
pt-BR

$ printf "%s\n" * | grep -E '^[A-Za-z]{1,8}(-[A-Za-z0-9]{1,8})*$'
eng
en-US
por
pt-BR

Ou apenas com o Bash:

$ for f in * ; do 
   [[ $f =~ ^[A-Za-z]{1,8}(-[A-Za-z0-9]{1,8})*$ ]] && printf "%s\n" "$f" ; done
eng
en-US
por
pt-BR

(A construção [[ .. ]] test é especial, as chaves e parênteses têm um significado diferente dentro dela, e de fato a regex deve estar sem aspas aqui. Observe que isso é totalmente diferente de [ .. ] Veja, por exemplo, BashGuide em condicionais )

A parte [a-zA-Z]{1,8} corresponde a strings de até oito letras, e a% final * permite um número arbitrário de repetições do grupo entre parênteses, então isso corresponderia a algo como foobar-foobar-foobar também.

Poderíamos alterar o padrão para ^[A-Za-z]{2,3}(-[A-Za-z0-9]{2,3})?$ apenas para permitir códigos com duas ou três letras e apenas uma parte -xx , se isso for tudo o que você precisa.

{1,8} sem aspas é expansão de chaves :

$ echo ^[A-Za-z]{1,8}
^[A-Za-z]1 ^[A-Za-z]8

e [] sem aspas é uma correspondência de padrões de nomes de arquivo (glob) ...

$ touch "^a1" "^b8"
$ echo ^[A-Za-z]{1,8}
^a1 ^b8
    
por 15.01.2018 / 10:17
2

Primeiro, você precisa citar o regex conforme os requisitos do grep usando grep 'regex'

Em seguida, você usará o suporte de regex estendido no grep usando egrep ou grep -E e isso funcionará ok:

$ ls | egrep '^[a-z]{2}-[A-Z]{2}$'

ou você pode usar a expressão regular clássica do grep, mas precisa escapar de { e } :

$ ls | grep '^[a-z]\{2\}-[A-Z]\{2\}$'

Para esses dados conforme sua pergunta

$ ls
eng
en-US
main.sh
por
pt-BR

A saída nos dois casos do grep será

en-US
pt-BR
    
por 15.01.2018 / 10:17
1
  1. Esta é uma expressão regular estendida, portanto, use -E
  2. Se você usar o padrão de pesquisa com caracteres especiais, cite-os

grep -E "^[a-z]{2}-[A-Z]{2}$"

    
por 15.01.2018 / 10:17