Por que o asterisco [a-z] corresponde aos números?

13

Eu tenho 3 diretórios no caminho atual.

$ls
a_0db_data  a_clean_0db_data  a_clean_data
$ls a_*_data
a_0db_data:

a_clean_0db_data:

a_clean_data:

$ls a_[a-z]*_data
a_clean_0db_data:

a_clean_data:

Eu esperava que o último comando ls correspondesse apenas a a_clean_data . Por que isso também corresponde ao que contém 0 ?

bash --version
GNU bash, version 4.2.24(1)-release (i686-pc-linux-gnu)
    
por user13107 10.09.2014 / 10:26

3 respostas

29

A parte [a-z] não é o que corresponde ao número; é o * . Você pode estar confundindo expressões globbing e regulares / a>.

Ferramentas como grep aceitam vários tipos de regexes ( básico por padrão, -E para estendido, -P para regex Perl )

Por exemplo ( -v inverte o jogo)

$ ls a_[a-z]*_data | grep -v "[0-9]"
a_clean_data

Se você quiser usar um regex bash, aqui está um exemplo de como testar se a variável $ref é um inteiro:

re='^[0-9]+$'
if ! [[ $ref =~ $re ]] ; then
  echo "error"
fi
    
por 10.09.2014 / 10:36
19

Então, o problema é: por que a_[a-z]*_data corresponde a a_clean_0db_data ?

Isso pode ser dividido em quatro partes:

  • a_ corresponde ao início de a_clean_0db_data , deixando clean_0db_data para ser correspondido

  • [a-z] corresponde a qualquer caractere no intervalo a-z (por exemplo, c ), deixando que lean_0db_data seja correspondido

  • * corresponde a qualquer número de caracteres, por ex. lean_0db

  • _data corresponde ao _data

Em expressões regulares, [a-z]* significaria qualquer número de caracteres (incluindo zero) no intervalo de a..z , mas você está lidando com globalização de shell, não com expressões regulares. / p>

Se você quiser expressões regulares, algumas find implementações têm um predicado -regex para isso:

find . -maxdepth 1 -regex "^.*/a_[a-z]*_data$"

O -maxdepth está aqui apenas para limitar os resultados da pesquisa à pasta em que você está. A expressão regular corresponde ao nome do arquivo inteiro , portanto, eu adicionei um ^.*/ para corresponder à parte do caminho

    
por 10.09.2014 / 10:41
10

* nos padrões de shell corresponde a 0 ou mais caracteres. Não deve ser confundido com o operador de expressão regular * que significa 0 ou mais do átomo anterior .

Não há equivalente de regexp * em padrões básicos de shell. No entanto, vários shells têm extensões para isso.

  • ksh tem *(something) :

    ls a_*([a-z])_data
    
  • você pode ter o mesmo em bash com shopt -s extglob ou zsh com setopt kshglob :

    shopt -s extglob
    ls a_*([a-z])_data
    
  • Em zsh com extendedglob ativado, # é equivalente a regexp * :

    setopt extendedglob
    ls a_[a-z]#_data
    
  • Nas versões recentes de ksh93 , você também pode usar expressões regulares em globs. Aqui com expressões regulares estendidas :

    ls ~(E:a_[a-z]*_data)
    

Observe que [a-z] corresponde a coisas diferentes, dependendo da localidade atual. Geralmente, corresponde apenas às letras não acentuadas de 26 a a z latin na C locale. Em outras localidades, geralmente corresponde mais e nem sempre faz sentido. Para corresponder a uma letra na sua localidade, você pode preferir [[:alpha:]] .

    
por 10.09.2014 / 11:16