Qual seria a melhor maneira de verificar se $ 1 é um número inteiro em / bin / dash?
No bash, eu poderia fazer:
[[ $1 =~ ^([0-9]+)$ ]]
Mas isso não parece ser compatível com POSIX e o traço não suporta esse
Qual seria a melhor maneira de verificar se $ 1 é um número inteiro em / bin / dash?
No bash, eu poderia fazer:
[[ $1 =~ ^([0-9]+)$ ]]
Mas isso não parece ser compatível com POSIX e o traço não suporta esse
Respostas:
Os seguintes detectam números inteiros, positivos ou negativos, e trabalham sob dash
e são POSIX:
echo "$1" | grep -Eq '^[+-]?[0-9]+$' && echo "It's an integer"
case "${1#[+-]}" in
''|*[!0-9]*)
echo "Not an integer" ;;
*)
echo "Integer" ;;
esac
Ou, com um pouco de uso do :
comando (nop):
! case ${1#[+-]} in *[!0-9]*) :;; ?*) ! :;; esac && echo Integer
Se dash
, bash
, ksh
, zsh
, POSIX sh
, ou posh
( "uma reimplementação do shell Bourne" sh
); o case
construto é o mais amplamente disponível e confiável:
case $1 in (*[!0-9]*|"") false ;; (*) true ;; esac
dash
? Funciona para mim sob, bash
mas não dash
.
dash
; para interrogar o resultado que adicionei echo $?
após o comando case.
posh
("uma reimplementação do shell Bourne") também não tem problemas com essa solução.
case
; um motivo é o bug que você descreve, outro que, nos editores que possuem recursos que dependem de parênteses correspondentes (vim), oferece suporte muito melhor e, não menos importante, acho pessoalmente mais legível tê-los emparelhados. - WRT posh
sendo POSIX; bem, a citação da página de manual que eu sugeri sugeriu outra coisa, mas não se pode confiar em tais declarações informais de qualquer maneira, eu acho. De qualquer forma, a velha casca de bourne não é tão significativa agora que estamos na era POSIX.
Você pode usar o -eq
teste na string, com ela mesma:
$ dash -c 'a="a"; if [ "$a" -eq "$a" ] ; then echo number; else echo not a number; fi'
dash: 1: [: Illegal number: a
not a number
$ dash -c 'a="0xa"; if [ "$a" -eq "$a" ] ; then echo number; else echo not a number; fi'
dash: 1: [: Illegal number: 0xa
not a number
$ dash -c 'a="-1"; if [ "$a" -eq "$a" ] ; then echo number; else echo not a number; fi'
number
Se a mensagem de erro for um problema, redirecione a saída de erro para /dev/null
:
$ dash -c 'a="0xa"; [ "$a" -eq "$a" ] 2>/dev/null|| echo no'
no
" 023 "
é um número. Observe que ele funciona com traço, mas nem todos os outros shells POSIX, pois o comportamento não é especificado se os operandos forem números inteiros decimais. Por exemplo, com o ksh, diria isso SHLVL
ou 1+1
é um número.
Tente usá-lo como uma expansão aritmética e veja se funciona. Na verdade, você precisa ser um pouco mais rigoroso do que isso, porque expansões aritméticas ignorariam os espaços iniciais e finais, por exemplo. Faça uma expansão aritmética e verifique se o resultado expandido corresponde exatamente à variável original.
check_if_number()
{
if [ "$1" = "$((${1}))" ] 2>/dev/null; then
echo "Number!"
else
echo "not a number"
fi
}
Isso também aceitaria números negativos - se você realmente quiser excluí-los, adicione uma verificação extra $((${1} >= 0))
.
[[
$(( ... ))
? Nesse caso, minha resposta ainda deve estar materialmente correta, só preciso adicionar algumas citações extras.
check_if_number 1.2
e a função retornou: dash: 3: arithmetic expression: expecting EOF: "1.2"
Talvez com expr
?
if expr match "$1" '^\([0-9]\+\)$' > /dev/null; then
echo "integer"
else
echo "non-integer"
fi
match
nem \+
são POSIX. Também diria que 0 não é um número. Você querexpr "x$1" : 'x[0-9]\{1,\}$'
No sistema POSIX, você pode usar expr :
$ a=a
$ expr "$a" - 0 >/dev/null 2>&1
$ [ "$?" -lt 2 ] && echo Integer || echo Not Integer
expr
implementações dirão que 9999999999999999999 não é um número inteiro. O POSIX não oferece garantia de que isso funcionará. Na prática, pelo menos em um sistema GNU, ele dirá que "length" é um número inteiro.
expr 9999999999999999999 + 0
me dá um status 3 saída e expr -12 + 0
e expr length + 0
me dar um status de saída 0 com GNU expr ( + string
forças string
a serem consideradas como uma string com o GNU expr
. expr "$a" - 0
Funcionaria melhor).
-12
é um número inteiro válido, e 9999999999999999999
deu um estouro.
Aqui está uma função simples usando o mesmo método da resposta do muru :
IsInteger() # usage: IsInteger string
{ # returns: flag
[ "$1" -eq "$1" ] 2> /dev/null
}
Exemplo:
p= n=2a3; IsInteger $n || p="n't" ; printf "'%s' is%s an integer\n" "$n" "$p"
p= n=23; IsInteger $n || p="n't" ; printf "'%s' is%s an integer\n" "$n" "$p"
Resultado:
'2a3' isn't an integer
'23' is an integer
foo\n123\nbar
não é um número inteiro, mas passaria nesse teste.