variable una resultado guardar funciones entorno ejemplos cómo crear comando linux bash shell

una - variables de entorno linux bash



¿Cómo puedo probar si una variable es un número en Bash? (30)

Simplemente no puedo entender cómo me aseguro de que un argumento pasado a mi script sea un número o no.

Todo lo que quiero hacer es algo como esto:

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

¿Alguna ayuda?


Antigua pregunta, pero solo quería seguir con mi solución. Este no requiere ningún truco de shell extraño, o confiar en algo que no ha existido desde siempre.

if [ -n "$(printf ''%s/n'' "$var" | sed ''s/[0-9]//g'')" ]; then echo ''is not numeric'' else echo ''is numeric'' fi

Básicamente, solo elimina todos los dígitos de la entrada, y si te quedan con una cadena que no es de cero, entonces no fue un número.


Como tuve que manipular esto últimamente y como karttu nombrar con la prueba de la unidad más. Revisé el código y también agregué algunas otras soluciones, pruébelo usted mismo para ver los resultados:

#!/bin/bash # N={0,1,2,3,...} by syntaxerror function isNaturalNumber() { [[ ${1} =~ ^[0-9]+$ ]] } # Z={...,-2,-1,0,1,2,...} by karttu function isInteger() { [[ ${1} == ?(-)+([0-9]) ]] } # Q={...,-½,-¼,0.0,¼,½,...} by karttu function isFloat() { [[ ${1} == ?(-)@(+([0-9]).*([0-9])|*([0-9]).+([0-9]))?(E?(-|+)+([0-9])) ]] } # R={...,-1,-½,-¼,0.E+n,¼,½,1,...} function isNumber() { isNaturalNumber $1 || isInteger $1 || isFloat $1 } bools=("TRUE" "FALSE") int_values="0 123 -0 -123" float_values="0.0 0. .0 -0.0 -0. -.0 / 123.456 123. .456 -123.456 -123. -.456 / 123.456E08 123.E08 .456E08 -123.456E08 -123.E08 -.456E08 / 123.456E+08 123.E+08 .456E+08 -123.456E+08 -123.E+08 -.456E+08 / 123.456E-08 123.E-08 .456E-08 -123.456E-08 -123.E-08 -.456E-08" false_values="blah meh mooh blah5 67mooh a123bc" for value in ${int_values} ${float_values} ${false_values} do printf " %5s=%-30s" $(isNaturalNumber $value) ${bools[$?]} $(printf "isNaturalNumber(%s)" $value) printf "%5s=%-24s" $(isInteger $value) ${bools[$?]} $(printf "isInteger(%s)" $value) printf "%5s=%-24s" $(isFloat $value) ${bools[$?]} $(printf "isFloat(%s)" $value) printf "%5s=%-24s/n" $(isNumber $value) ${bools[$?]} $(printf "isNumber(%s)" $value) done

Así que isNumber () incluye guiones, comas y notación exponencial y, por lo tanto, devuelve VERDADERO en enteros y flotantes, mientras que, por otro lado, isFloat () devuelve FALSE en valores enteros y isInteger () también devuelve FALSE en floats. Para su conveniencia todos como liners:

isNaturalNumber() { [[ ${1} =~ ^[0-9]+$ ]]; } isInteger() { [[ ${1} == ?(-)+([0-9]) ]]; } isFloat() { [[ ${1} == ?(-)@(+([0-9]).*([0-9])|*([0-9]).+([0-9]))?(E?(-|+)+([0-9])) ]]; } isNumber() { isNaturalNumber $1 || isInteger $1 || isFloat $1; }


Estaba mirando las respuestas y ... ¡me di cuenta de que nadie pensó en los números de FLOAT (con punto)!

Usar grep también es genial.
-E significa expresión regular extendida
-q significa silencio (no hace eco)
-qE es la combinación de ambos.

Para probar directamente en la línea de comando:

$ echo "32" | grep -E ^/-?[0-9]?/.?[0-9]+$ # answer is: 32 $ echo "3a2" | grep -E ^/-?[0-9]?/.?[0-9]+$ # answer is empty (false) $ echo ".5" | grep -E ^/-?[0-9]?/.?[0-9]+$ # answer .5 $ echo "3.2" | grep -E ^/-?[0-9]?/.?[0-9]+$ # answer is 3.2

Usando en un script bash:

check=`echo "$1" | grep -E ^/-?[0-9]*/.?[0-9]+$` if [ "$check" != '''' ]; then # it IS numeric echo "Yeap!" else # it is NOT numeric. echo "nooop" fi

Para hacer coincidir enteros JUSTOS, usa esto:

# change check line to: check=`echo "$1" | grep -E ^/-?[0-9]+$`


Esto prueba si un número no es un número entero negativo y es independiente de shell (es decir, sin bashismos) y usa solo shell incorporado:

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

PERO ES INCORRECTO .
Como jilles comentó y sugirió en jilles esta es la forma correcta de hacerlo usando patrones de shell.

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


He encontrado una versión bastante corta:

function isnum() { return `echo "$1" | awk -F"/n" ''{print ($0 != $0+0)}''` }


La forma más sencilla es verificar si contiene caracteres sin dígitos. Reemplaza todos los caracteres de dígitos con nada y verifica la longitud. Si hay longitud no es un número.

if [[ ! -n ${input//[0-9]/} ]]; then echo "Input Is A Number" fi


La siguiente solución también se puede utilizar en shells básicos como Bourne sin necesidad de expresiones regulares. Básicamente, cualquier operación de evaluación de valor numérico que use números que no sean números resultará en un error que se considerará implícitamente como falso en el 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 puede probar por $? 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 de "expresión entera esperada" que imprime bash en caso de que no tengamos un número.

CUEVAS (gracias a los comentarios a continuación):

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

Me sorprende que las soluciones analicen directamente los formatos de números en shell. Shell no es adecuado para esto, ya que es un DSL para controlar archivos y procesos. Hay muchos analizadores 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'' a cualquier formato particular que requiera.



No puedo comentar aún, así que agregaré mi propia respuesta, que es una extensión de la respuesta de glenn jackman utilizando la coincidencia de patrones de bash.

Mi necesidad original era identificar números y distinguir enteros y flotadores. Las definiciones de funciones deducidas a:

function isInteger() { [[ ${1} == ?(-)+([0-9]) ]] } function isFloat() { [[ ${1} == ?(-)@(+([0-9]).*([0-9])|*([0-9]).+([0-9]))?(E?(-|+)+([0-9])) ]] }

Utilicé pruebas de unidad (con shUnit2) para validar mis patrones que funcionaron según lo previsto:

oneTimeSetUp() { int_values="0 123 -0 -123" float_values="0.0 0. .0 -0.0 -0. -.0 / 123.456 123. .456 -123.456 -123. -.456 123.456E08 123.E08 .456E08 -123.456E08 -123.E08 -.456E08 / 123.456E+08 123.E+08 .456E+08 -123.456E+08 -123.E+08 -.456E+08 / 123.456E-08 123.E-08 .456E-08 -123.456E-08 -123.E-08 -.456E-08" } testIsIntegerIsFloat() { local value for value in ${int_values} do assertTrue "${value} should be tested as integer" "isInteger ${value}" assertFalse "${value} should not be tested as float" "isFloat ${value}" done for value in ${float_values} do assertTrue "${value} should be tested as float" "isFloat ${value}" assertFalse "${value} should not be tested as integer" "isInteger ${value}" done }

Notas: El patrón isFloat se puede modificar para que sea más tolerante con el punto decimal ( @(.,) ) Y el símbolo E ( @(Ee) ). Mis pruebas de unidad solo prueban valores que son enteros o flotantes, pero no entradas inválidas.


Para atrapar números negativos:

if [[ $1 == ?(-)+([0-9.]) ]] then echo number else echo not a number fi


Probé la receta de ultrasawblade ya que me pareció la más práctica, y no pude hacerla funcionar. Sin embargo, al final diseñé otra forma, basada como otras en la sustitución de parámetros, esta vez con el reemplazo de expresiones regulares:

[[ "${var//*([[:digit:]])}" ]]; && echo "$var is not numeric" || echo "$var is numeric"

Elimina cada carácter de: dígito: clase en $ var y comprueba si nos queda una cadena vacía, lo que significa que el original era solo números.

Lo que me gusta de este es su pequeña huella y flexibilidad. De esta forma, solo funciona con enteros de base 10 no delimitados, aunque seguramente puede usar la coincidencia de patrones para adaptarla a otras necesidades.


Rápido y sucio: Sé que no es la forma más elegante, pero por lo general le agregué un cero y probé el resultado. al igual que:

function isInteger { [ $(($1+0)) != 0 ] && echo "$1 is a number" || echo "$1 is not a number" } x=1; isInteger $x x="1"; isInteger $x x="joe"; isInteger $x x=0x16 ; isInteger $x x=-32674; isInteger $x

$ (($ 1 + 0)) devolverá 0 o bomba si $ 1 NO es un número entero. por ejemplo:

function zipIt { # quick zip - unless the 1st parameter is a number ERROR="not a valid number. " if [ $(($1+0)) != 0 ] ; then # isInteger($1) echo " backing up files changed in the last $1 days." OUT="zipIt-$1-day.tgz" find . -mtime -$1 -type f -print0 | xargs -0 tar cvzf $OUT return 1 fi showError $ERROR }

NOTA: Supongo que nunca pensé en buscar flotadores o tipos mixtos que harán que todo el script sea una bomba ... en mi caso, no quería que fuera más allá. Voy a jugar un poco con la solución de mrucci y la expresión regular de Duffy, parecen ser las más robustas dentro del marco de bash ...


Sólo un seguimiento a @mary. Pero como no tengo suficiente representante, no pude publicar esto como un comentario para esa publicación. De todos modos, aquí está lo que he usado:

isnum() { awk -v a="$1" ''BEGIN {print (a == a + 0)}''; }

La función devolverá "1" si el argumento es un número, de lo contrario devolverá "0". Esto funciona tanto para enteros como para flotadores. El uso es algo como:

n=-2.05e+07 res=`isnum "$n"` if [ "$res" == "1" ]; then echo "$n is a number" else echo "$n is not a number" fi


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

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

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

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


Un enfoque es usar una expresión regular, como así:

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

Si el valor no es necesariamente un número entero, considere enmendar la expresión regular de manera apropiada; por ejemplo:

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

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

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


Ya se ha dado una respuesta clara por @charles Dufy y otros. Una solución de bash pura estaría usando lo siguiente:

string="-12,345" if [[ "$string" =~ ^-?[0-9]+[.,]?[0-9]*$ ]] then echo $string is a number else echo $string is not a number fi

Aunque para los números reales no es obligatorio tener un número antes del punto radix .

Para proporcionar un soporte más completo de los números flotantes y la notación científica (muchos programas en C / Fortran o bien exportarán de esta manera), una adición útil a esta línea sería la siguiente:

string="1.2345E-67" if [[ "$string" =~ ^-?[0-9]*[.,]?[0-9]*[eE]?-?[0-9]+$ ]] then echo $string is a number else echo $string is not a number fi

Por lo tanto, puede buscar una forma de diferenciar los tipos de números, si está buscando algún tipo específico:

string="-12,345" if [[ "$string" =~ ^-?[0-9]+$ ]] then echo $string is an integer elif [[ "$string" =~ ^-?[0-9]*[.,]?[0-9]*$ ]] then echo $string is a float elif [[ "$string" =~ ^-?[0-9]*[.,]?[0-9]*[eE]-?[0-9]+$ ]] then echo $string is a scientific number else echo $string is not a number fi

Nota: podríamos enumerar los requisitos sintácticos para la notación decimal y científica, uno de los cuales es permitir la coma como punto de raíz, así como ".". Entonces, afirmaríamos que solo debe haber uno de estos puntos radix. Puede haber dos signos +/- en un flotador [Ee]. Aprendí algunas reglas más del trabajo de Aulu, y probé contra cadenas malas como '''' ''-'' ''-E-1'' ''0-0''. Aquí están mis herramientas regex / substring / expr que parecen aguantar:

parse_num() { local r=`expr "$1" : ''.*/([.,]/)'' 2>/dev/null | tr -d ''/n''` nat=''^[+-]?[0-9]+[.,]?$'' / dot="${1%[.,]*}${r}${1##*[.,]}" / float=''^[/+/-]?([.,0-9]+[Ee]?[-+]?|)[0-9]+$'' [[ "$1" == $dot ]] && [[ "$1" =~ $float ]] || [[ "$1" =~ $nat ]] } # usage: parse_num -123.456


Yo intentaría esto:

printf "%g" "$var" &> /dev/null if [[ $? == 0 ]] ; then echo "$var is a number." else echo "$var is not a number." fi

Nota: esto reconoce a nan e inf como número.


Yo uso expr . Devuelve un valor distinto de cero si intenta agregar un cero a un valor no numérico:

if expr $number + 0 > /dev/null 2>&1 then echo "$number is a number" else echo "$number isn''t a number" fi

Podría ser posible usar bc si necesita no enteros, pero no creo que bc tenga el mismo comportamiento. Agregar cero a un no-número le da cero y también devuelve un valor de cero. Tal vez puedas combinar bc y expr . Use bc para agregar cero a $number . Si la respuesta es 0 , intente expr para verificar que $number no es cero.


Yo uso lo siguiente (para enteros):

## ##### constants ## ## __TRUE - true (0) ## __FALSE - false (1) ## typeset -r __TRUE=0 typeset -r __FALSE=1 ## -------------------------------------- ## isNumber ## check if a value is an integer ## usage: isNumber testValue ## returns: ${__TRUE} - testValue is a number else not ## function isNumber { typeset TESTVAR="$(echo "$1" | sed ''s/[0-9]*//g'' )" [ "${TESTVAR}"x = ""x ] && return ${__TRUE} || return ${__FALSE} } isNumber $1 if [ $? -eq ${__TRUE} ] ; then print "is a number" fi


http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_04_03.html

También puedes usar las clases de personajes de bash.

if [[ $VAR = *[[:digit:]]* ]]; then echo "$VAR is numeric" else echo "$VAR is not numeric" fi

Los números incluirán el espacio, el punto decimal y "e" o "E" para el punto flotante.

Pero, si especifica un número hexadecimal de estilo C, es decir, "0xffff" o "0XFFFF", [[: dígito:]] devuelve verdadero. Una pequeña trampa aquí, bash te permite hacer algo como "0xAZ00" y aún así contarla como un dígito (¿no es esto de alguna extraña peculiaridad de los compiladores GCC que te permiten usar la notación 0x para otras bases que no sean 16? )

Es posible que desee probar "0x" o "0X" antes de probar si es numérico si su entrada no es confiable, a menos que desee aceptar números hexadecimales. Eso se lograría mediante:

if [[ ${VARIABLE:1:2} = "0x" ]] || [[ ${VARIABLE:1:2} = "0X" ]]; then echo "$VAR is not numeric"; fi


Hizo lo mismo aquí con una expresión regular que prueba la parte entera y la parte de los decimales, separados con un punto.

re="^[0-9]*[.]{0,1}[0-9]*$" if [[ $1 =~ $re ]] then echo "is numeric" else echo "Naahh, not numeric" fi


Me gusta la respuesta de Alberto Zaccagni.

if [ "$var" -eq "$var" ] 2>/dev/null; then

Prerrequisitos importantes: - no se generan subshells - no se invocan analizadores RE - la mayoría de las aplicaciones de shell no usan números reales

Pero si $vares complejo (por ejemplo, un acceso de matriz asociativa), y si el número será un entero no negativo (en la mayoría de los casos de uso), ¿quizás esto sea más eficiente?

if [ "$var" -ge 0 ] 2> /dev/null; then ..


Podrías usar "let" también así:

[ ~]$ var=1 [ ~]$ let $var && echo "It''s a number" || echo "It''s not a number" It/'s a number [ ~]$ var=01 [ ~]$ let $var && echo "It''s a number" || echo "It''s not a number" It/'s a number [ ~]$ var=toto [ ~]$ let $var && echo "It''s a number" || echo "It''s not a number" It/'s not a number [ ~]$

Pero prefiero usar el operador "= ~" Bash 3+ como algunas respuestas en este hilo.


Siguiendo con share de share 13 de octubre, si usar expresto podría ser mejor

test_var=`expr $am_i_numeric /* 0` >/dev/null 2>&1 if [ "$test_var" = "" ] then ......

Si es numérico, multiplicado por 1 le da el mismo valor (incluidos los números negativos). De lo contrario obtienes nulllo que puedes probar


Uso printf como otras respuestas mencionadas, si proporciona la cadena de formato "% f" o "% i" printf hará la comprobación por usted. Más fácil que reinventar los cheques, la sintaxis es simple y corta y la impresión es ubicua. Así que, en mi opinión, es una opción decente: también puede utilizar la siguiente idea para verificar una serie de cosas, no solo es útil para verificar números.

declare -r CHECK_FLOAT="%f" declare -r CHECK_INTEGER="%i" ## <arg 1> Number - Number to check ## <arg 2> String - Number type to check ## <arg 3> String - Error message function check_number() { local NUMBER="${1}" local NUMBER_TYPE="${2}" local ERROR_MESG="${3}" local -i PASS=1 local -i FAIL=0 case "${NUMBER_TYPE}" in "${CHECK_FLOAT}") if ((! $(printf "${CHECK_FLOAT}" "${NUMBER}" &>/dev/random;echo $?))); then echo "${PASS}" else echo "${ERROR_MESG}" 1>&2 echo "${FAIL}" fi ;; "${CHECK_INTEGER}") if ((! $(printf "${CHECK_INTEGER}" "${NUMBER}" &>/dev/random;echo $?))); then echo "${PASS}" else echo "${ERROR_MESG}" 1>&2 echo "${FAIL}" fi ;; *) echo "Invalid number type format: ${NUMBER_TYPE} to check_number()." 1>&2 echo "${FAIL}" ;; esac }

>$ var=45

>$ (($(check_number $var "${CHECK_INTEGER}" "Error: Found $var - An integer is required."))) && { echo "$var+5" | bc; }


[[ $1 =~ ^-?[0-9]+$ ]] && echo "number"

¡No olvides incluir números negativos!


printf ''%b'' "-123/nABC" | tr ''[:space:]'' ''_'' | grep -q ''^-/?[[:digit:]]/+$'' && echo "Integer." || echo "NOT integer."

Elimine el -/?patrón de coincidencia en grep si no acepta un entero negativo.


test -z "${i//[0-9]}" && echo digits || echo no no no

${i//[0-9]} reemplaza cualquier dígito en el valor de $i con una cadena vacía, vea man -P ''less +/parameter//'' bash . -z comprueba si la cadena resultante tiene longitud cero.

Si también desea excluir el caso cuando $i está vacío, puede usar una de estas construcciones:

test -n "$i" && test -z "${i//[0-9]}" && echo digits || echo not a number [[ -n "$i" && -z "${i//[0-9]}" ]] && echo digits || echo not a number


  • variable a verificar

    number=12345 o number=-23234 o number=23.167 o number=-345.234

  • comprobar numérico o no numérico

    echo $number | grep -E ''^-?[0-9]*/.?[0-9]*$'' > /dev/null

  • Decidir sobre nuevas acciones basadas en el estado de salida de los anteriores

    if [ $? -eq 0 ]; then echo "Numeric"; else echo "Non-Numeric"; fi