Com a sintaxe POSIX sh:
#! /bin/sh -
printf 'Choose a decimal integer number between 1 and 100: '
IFS= read -r num
die() {
printf >&2 '%s\n' "$@"
exit 1
}
case $num in
("" | - | *[!0123456789-]* | ?*-*)
die "$num is not a valid decimal integer number";;
(*[123456789]??*)
die "You chose a number outside the boundaries"
esac
if [ "$num" -lt 1 ] || [ "$num" -gt 100 ]; then
die "You chose a number outside the boundaries"
fi
echo "You chose $num"
-
número é ambíguo.
0xAA
,MMXVIII
,¾
,010
,1.4e+4
,infinity
são todos números por alguma definição de número . Muitos shells do tipo POSIX, incluindobash
, suportam apenas inteiros decimais em seus[
builtin (e decimal, octal, hexadecimal em suas expressões aritméticas). É melhor qualificar exatamente o tipo de número desejado. Aqui inteiro decimal, por exemplo. -
O uso de cadeias arbitrárias em uma expressão aritmética e em alguns shells no comando
[
é uma vulnerabilidade de injeção de comando . Então você gostaria de verificar se o número de entrada se parece com um número primeiro. -
IFS= read -r line
é a sintaxe para ler uma linha de entrada (embora aqui a manipulação$IFS
-stripping e continuação de linha deread num
provavelmente seja OK). - expansões de parâmetros precisam ser citadas em shells semelhantes a Bourne
- Você teve uma falha na sua lógica. Você usou ou em vez de e . Todos os números decimais são maiores que 1 ou menos que 100.
- Os operadores
-o
e-a
[
estão obsoletos conforme fazem para expressões de teste que não podem ser interpretadas de forma confiável. Enquanto aqui, não seria um problema, uma vez que tenhamos certeza de que os argumentos são números inteiros decimais, eles devem ser evitados. É melhor usar várias invocações de[
separadas por&&
ou||
de operadores de shell. - É melhor enviar mensagens de erro no stderr (
>&2
) e sair com um status de saída diferente de zero em caso de falha. - A maioria dos shells usa os tipos de dados inteiros do compilador para seus operadores inteiros. Para a maioria dos shells na maioria dos sistemas, 2 64 +50 por exemplo (18446744073709551666) seria muito grande para essa representação interna. Dependendo da implementação
[
do shell, ele não seria reconhecido como um número (bash, dash, yash), truncado para 19 dígitos com um aviso (zsh), aproximado como um número flutuante (ksh93) ou considerado como o mesmo que 50) (mksh). Portanto, você pode descobrir que[ 18446744073709551666 -gt 0 ]
retorna falso ou que[ 18446744073709551666 -le 100 ]
retorna verdadeiro. Daí a verificação*[123456789]??*
para mais de 3 dígitos. - observe que, se o usuário inserir um caractere NUL como parte de sua entrada, o comportamento variará entre os shells.
Com bash
especificamente, você pode deixar um pouco menos complicado com:
#! /bin/bash -
IFS= read -rp 'Choose a decimal integer number between 1 and 100: ' num
die() {
printf >&2 '%s\n' "$@"
exit 1
}
[[ $num =~ ^-?[0123456789]+$ ]] ||
die "$num is not a valid decimal integer number"
[[ $num = *[123456789]??* ]] ||
((num < 1 || num > 100)) &&
die "You chose a number outside the boundaries"
echo "You chose $num"