Eu quero verificar se um argumento para um script de shell é um número inteiro (ou seja, um número inteiro não negativo: 0, 1, 2, 3, …, 17, …, 42, …, etc, mas não 3,1416 ou −5 ) expresso em decimal (portanto, nada como 0x11 ou 0x2A). Como posso escrever uma instrução de caso usando regex como condição (para corresponder a números)? Eu tentei algumas maneiras diferentes que encontrei (por exemplo, [0-9]+
ou ^[0-9][0-9]*$
); nenhum deles funciona. Como no exemplo a seguir, os números válidos estão caindo no regex numérico que deve capturá-los e correspondem ao *
curinga.
i=1
let arg_n=$#+1
while (( $i < $arg_n )); do
case ${!i} in
[0-9]+)
n=${!i}
;;
*)
echo 'Invalid argument!'
;;
esac
let i=$i+1
done
Resultado:
$ ./cmd.sh 64
Invalid argument!
case
não usa regexes, usa padrõesPara "1 ou mais dígitos", faça o seguinte:
Se você quiser usar expressões regulares, use o
=~
operador dentro[[...]]
Como diz glenn , “
case
não usa regexes, usa padrões ”. Como bash(1) diz,Da mesma forma, a especificação POSIX diz,
Portanto, os padrões são padrões de expansão de nome de caminho, também conhecidos como curingas, também conhecidos como globs, como em
ls -l -- *.sh
ourm -- *.bak
.Claro,
shopt -s extglob
e[[ … =~ … ]]
são a coisa mais legal desde o pão fatiado, mas não são POSIX e pode ser útil saber como usar as ferramentas originais. Durante anos, os programadores verificaram, por exemplo, se uma string era um número verificando se não era um número. Você definiu um número como uma string que consiste (totalmente) em um ou mais dígitos. Portanto, uma string não é um número se for nula ou se contiver um caractere que não seja um dígito. Podemos testar essas condições com umacase
declaração como segue:onde
[!0-9]
é a velha maneira de dizer[^0-9]
, que, é claro, significa qualquer caractere que não seja um dígito. ([!…]
e[^…]
ambos funcionam em bash.[!…]
é necessário para funcionar com POSIX; o resultado de[^…]
não é especificado.) Se você não se importa com o tipo de não número de uma string, pode combinar os padrões não numéricos:Como exercício, aqui está uma
case
instrução para lidar com qualquer tipo de número real — para ser mais preciso, uma string de um ou mais dígitos, opcionalmente com um ponto (.
) em algum lugar e, opcionalmente, um sinal de menos (-
) no início.Eu adicionei o
case
-within-a-case
para verificar se a string contém, de fato, pelo menos um dígito. Isso não foi necessário no exemplo inteiro porque testei se a string era nula; um teste que removi desta declaração. Sem o segundocase
, um único-
ou um único.
— ou mesmo-.
— se qualificaria como um número. Claro que poderíamos adicionar padrões para lidar com essas exceções, mas isso pode se tornar complexo. (Por exemplo, quase postei esta resposta sem perceber que-.
era uma das exceções.) Acredito que a abordagem acima é mais flexível e robusta.É claro que os padrões não numéricos também podem ser combinados aqui:
(*[!-.0-9]* | *?-* | *.*.*)
.Para combinar números com regexp em
case
declarações , você precisa de um shell cujos curingas suportem regexps. Eu só sei de ksh93 com aqueles.Com globs ksh93, você pode fazer
~(E)^[0-9]+$
ou~(E:^[0-9]+$)
usar umE
regexp xtended em um padrão glob ou~(P)^\d+$
usar um regexp semelhante a perl (tambémG
para regexp básico,X
para regexp aumentada,V
para regexp SysV).Então: