Regex para verificar apenas números estão presentes após sublinhado e não caracteres

5

Eu tenho se loop no meu script de shell que irá verificar o é o nome da tabela está tendo qualquer inteiro presente esta é a condição que estou especificando:

if [[ "$able_name" == *[0-9]* ]] 

Geralmente, o nome da tabela será assim:

tablename_000 

ou

tablename_001 

Mas eu tenho um novo arquivo cujo nome é algo como table_V2 . Como o nome corresponde ao regex, ele está entrando nesse loop. Como posso evitar isso? Ele deve inserir o loop if somente se números inteiros estiverem presentes após o sublinhado e não qualquer outro caractere.

    
por Rahul 12.10.2017 / 16:39

4 respostas

5

Com a sintaxe sh padrão:

case ${table_name##*_} in
  ("$table_name" | "" | *[!0-9]*) echo >&2 incorrect;;
  (*) echo correct;;
esac

Isso é verificar se $table_name de tudo despojado até o nível mais alto _ não é $table_name (o que significa $table_name não tem _ ), nem a string vazia, nem continha um caractere não digitável.

O comando padrão para corresponder uma string a um regexp é expr , embora tenha alguns problemas e não um código muito legível:

if expr " $table_name" : '.*_[0-9]\{1,\}$' > /dev/null; then
  echo Correct
else
  echo >&2 Incorrect
fi

O espaço principal é evitar problemas com valores de $table_name , como + ou --help . regexps são ancorados no início implicitamente (daí o .* ) mas não no final (daí o $ ) e o resultado (0 ou 1 aqui) é gerado no stdout além de ser refletido no status de saída, daí o redirecionamento para / dev / null.

Algumas implementações [ como [ integradas de zsh e yash têm um operador =~ para isso (usando ERE, embora você possa alterar isso para PCRE com zsh ):

if [ "$table_name" '=~' '_[0-9]+$' ]; then
   echo Correct
else
   echo >&2 Incorrect
fi

bash , zsh e ksh93 têm um operador =~ dentro de sua construção [[...]] , embora a sintaxe e o comportamento entre aspas variem entre as implementações. O melhor é usar as variáveis como já foi mostrado por @BLayer

zsh -o extendedglob e ksh (ou bash -O extglob ou zsh -o kshglob que suportam um subconjunto de ksh globs) têm operadores glob que são funcionalmente equivalentes a regexps embora com uma sintaxe diferente.

Tradução RE - > ksh-glob / zsh-glob:

  • [0-9] - > [0-9] / [0-9]
  • x+ - > +(x) / x##
  • $ ou ^ - > implícito / implícito
  • . - > %código%
  • ? - > .* (ou * ) / *(?) (ou * )

Então, em ?# (ou ksh ou bash -O extglob ):

case $table_name in
  (*_+([0-9]) echo correct;;
  (*) echo >&2 incorrect;;
esac

Em zsh -o kshglob :

case $table_name in
  (*_[0-9]##) echo correct;;
  (*) echo >&2 incorrect;;
esac

zsh -o extendedglob também tem o operador zsh extended glob para corresponder números decimais de <x-y> a x , para que você também possa escrever y .

Nesses shells, esses globs também podem ser usados no lado direito do operador (*_<->) echo correct aka = == .

    
por 12.10.2017 / 16:44
3

Provavelmente o regex mais simples:

if [[ "$file" =~ _[0-9]+$ ]]
then
    echo OK $file
fi
    
por 12.10.2017 / 16:51
3

Muitas maneiras de fazer isso. Aqui está uma versão do Bash que segue o caminho regex tradicional (ou pelo menos a aproximação mais próxima do Bash):

pattern='^tablename_[[:digit:]]+$'
if [[ $filename =~ $pattern ]]; then
    echo "Filename $filename is valid"
fi

Algumas notas:

  • Para todos, exceto as expressões regulares mais simples, é recomendável usar uma variável, como fiz aqui com pattern . Mesmo que nenhuma divisão de palavra ou expansão de nome de caminho seja aplicada à expressão dentro de [[ ]] , haverá expansão de til, variável e aritmética, bem como substituição de processo e comando. É muito fácil obter resultados incorretos ou inesperados com regex inline.
  • Estou usando a classe de caracteres POSIX [:digit:] , mas 0-9 também. Eu percebi que a maioria das outras respostas aqui usaria o último e valeria a pena mostrar o primeiro por questão de completude

Comentário: O fato de haver tantas variações sobre esse tema (apenas neste segmento) é uma das razões pelas quais algumas pessoas não gostam de sh / bash ... e porque eu as amo . :)

    
por 12.10.2017 / 16:48
2

Recomende o uso de uma opção regex para isso, mas também é possível usar uma glob normal para dígitos. Por exemplo, você poderia fazer algo como

for file in tablename_[0-9]*; do
    [ -f "$file" ] || continue
    printf "%s\n" "$file"
done

Usando o operador regex em bash , você poderia fazer algo como

for file in tablename_*; do
    if [[ $file =~ _([[:digit:]]+)$ ]]; then
        printf "%s\n" "$file"
    fi
done
    
por 12.10.2017 / 16:43