446 votos

¿Cómo puedo comprobar si una variable es un número en Bash?

Es que no consigo averiguar cómo hago para asegurarme de que un argumento pasado a mi script es un número o no.

Todo lo que quiero hacer es algo así:

test *isnumber* $1 && VAR=$1 || echo "need a number"

¿Alguna ayuda?

596voto

Charles Duffy Puntos 34134

Un enfoque es utilizar una expresión regular, como la siguiente:

re='^[0-9]+$'
if ! [[ $yournumber =~ $re ]] ; then
   echo "error: Not a number" >&2; exit 1
fi

Si el valor no es necesariamente un entero, considere la posibilidad de modificar la expresión regular de forma adecuada; por ejemplo

^[0-9]+([.][0-9]+)?$

...o, para manejar los números con un signo:

^[+-]?[0-9]+([.][0-9]+)?$

213voto

jilles Puntos 4241

Sin bashismos (funciona incluso en el Sistema V sh),

case $string in
    ''|*[!0-9]*) echo bad ;;
    *) echo good ;;
esac

Esto rechaza las cadenas vacías y las que no contienen dígitos, aceptando todo lo demás.

Los números negativos o de punto flotante necesitan un trabajo adicional. Una idea es excluir - / . en el primer patrón "malo" y añadir más patrones "malos" que contengan los usos inadecuados de los mismos ( ?*-* / *.*.* )

140voto

Alberto Zaccagni Puntos 11478

La siguiente solución también puede utilizarse en shells básicos como Bourne sin necesidad de expresiones regulares. Básicamente, cualquier operación de evaluación de valores numéricos que no sean números dará lugar a un error que se considerará implícitamente como falso en Shell:

"$var" -eq "$var"

como en:

#!/bin/bash

var=a

if [ -n "$var" ] && [ "$var" -eq "$var" ] 2>/dev/null; then
  echo number
else
  echo not a number
fi

También se puede probar el código de retorno de la operación, que es más explícito:

[ -n "$var" ] && [ "$var" -eq "$var" ] 2>/dev/null
if [ $? -ne 0 ]; then
   echo $var is not number
fi

La redirección del error estándar está ahí para ocultar el mensaje "integer expression expected" que bash imprime en caso de que no tengamos un número.

CAVEATS (gracias a los comentarios de abajo):

  • Los números con puntos decimales son no identificados como "números" válidos
  • Utilizando [[ ]] en lugar de [ ] siempre se evaluará a true
  • La mayoría de los shells no-Bash siempre evaluarán esta expresión como true
  • El comportamiento en Bash no está documentado y, por tanto, puede cambiar sin previo aviso
  • Si el valor incluye espacios después del número (por ejemplo, "1 a") produce error, como bash: [[: 1 a: syntax error in expression (error token is "a")
  • Si el valor es el mismo que var-name (por ejemplo, i="i"), produce un error, como bash: [[: i: expression recursion level exceeded (error token is "i")

32voto

mrucci Puntos 1917

Esto comprueba si un número es un entero no negativo y es a la vez Shell independiente (es decir, sin bashismos) y utiliza sólo Shell built-ins:

INCORRECTO.

Como esta primera respuesta (abajo) permite números enteros con caracteres en ellos siempre que los primeros no sean los primeros en la variable.

[ -z "${num##[0-9]*}" ] && echo "is a number" || echo "is not a number";

CORRECTO .

Como jilles comentado y sugerido en su respuesta esta es la forma correcta de hacerlo usando Shell-patrones.

[ ! -z "${num##*[!0-9]*}" ] && echo "is a number" || echo "is not a number";

27voto

pixelbeat Puntos 12073

Me sorprenden las soluciones que analizan directamente los formatos numéricos en Shell. Shell no se adapta bien a esto, siendo un DSL para controlar archivos y procesos. Hay amplios parsers de números un poco más abajo, por ejemplo:

isdecimal() {
  # filter octal/hex/ord()
  num=$(printf '%s' "$1" | sed "s/^0*\([1-9]\)/\1/; s/'/^/")

  test "$num" && printf '%f' "$num" >/dev/null 2>&1
}

Cambie "%f" por el formato que desee.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X