/ bin / dash: verifica si $ 1 es un número

12

¿Cuál sería la mejor manera de verificar si $ 1 es un entero en / bin / dash?

En bash, podría hacer:

[[ $1 =~ ^([0-9]+)$ ]]

Pero eso no parece ser compatible con POSIX y el guión no es compatible con eso

Martin Vegter
fuente

Respuestas:

12

Los siguientes detectan enteros, positivos o negativos, y funcionan debajo dashy son POSIX:

Opción 1

echo "$1" | grep -Eq '^[+-]?[0-9]+$' && echo "It's an integer"

opcion 2

case "${1#[+-]}" in
    ''|*[!0-9]*)
        echo "Not an integer" ;;
    *)
        echo "Integer" ;;
esac

O, con un poco de uso del :comando (nop):

! case ${1#[+-]} in *[!0-9]*) :;; ?*) ! :;; esac && echo Integer
John1024
fuente
55
¿Qué pasa si la cadena contiene nuevas líneas? foo\n123\nbarno es un entero, pero pasaría esta prueba.
godlygeek
3
La versión grep, eso es. La versión del caso parece correcta.
godlygeek
5

Ya sea dash, bash, ksh, zsh, POSIX sh, o posh( "una reimplementación de la shell Bourne" sh ); El caseconstructo es el más ampliamente disponible y confiable:

case $1 in (*[!0-9]*|"") false ;; (*) true ;; esac
Janis
fuente
¿Probaste esto debajo dash? Funciona para mí debajo bashpero no dash.
John1024
Sí, lo probé en mi sistema también con dash; para interrogar el resultado que agregué echo $?después del comando del caso.
Janis
Hice lo mismo (Debian estable) pero no me alegro. Para un ejemplo completo que funciona para mí bajo mi guión, vea mi Opción 2 .
John1024
Hmm, no tengo una cáscara de bourne original disponible para probar. Los documentos que inspeccioné sobre "características [en ksh] no en bourne shell" al menos no lo mencionan, así que supongo que estaba allí. ¿No? - Luego omita el paréntesis principal. - OTOH, posh("una reimplementación del shell Bourne") tampoco tiene ningún problema con esa solución.
Janis
1
@mikeserv; Hay varias razones por las que uso siempre paréntesis coincidentes case; Una de las razones es el error que usted describe, otra que en los editores que tienen características que se basan en paréntesis coincidentes (vim) brinda un soporte mucho mejor, y no menos importante personalmente me parece más legible hacer que coincidan. - WRT poshsiendo POSIX; bueno, la cita de la página de manual que di sugirió algo más, pero supongo que no se puede confiar en declaraciones tan informales de todos modos. El viejo caparazón de bourne ya no es tan significativo ahora que estamos en la era POSIX.
Janis
1

Puede usar la -eqprueba en la cadena, consigo misma:

$ 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

Si el mensaje de error es un problema, redirija la salida del error a /dev/null:

$ dash -c 'a="0xa"; [ "$a" -eq "$a" ] 2>/dev/null|| echo no'
no
muru
fuente
1
También diría que " 023 "es un número. Tenga en cuenta que funciona con guiones, pero no todos los demás shells POSIX ya que el comportamiento no se especifica si los operandos son enteros decimales de nota. Por ejemplo con ksh, diría que SHLVLo 1+1es un número.
Stéphane Chazelas
0

Intente usarlo como una expansión aritmética y vea si funciona. En realidad, debe ser un poco más estricto que eso, porque las expansiones aritméticas ignorarían los espacios iniciales y finales, por ejemplo. Realice una expansión aritmética y asegúrese de que el resultado expandido coincida exactamente con la variable original.

check_if_number()
{
    if [ "$1" = "$((${1}))" ] 2>/dev/null; then
        echo "Number!"
    else
        echo "not a number"
    fi
}

Esto también aceptaría números negativos: si realmente quiere excluirlos, agregue un cheque adicional para $((${1} >= 0)).

Godlygeek
fuente
1
dash no tiene[[
glenn jackman
@glennjackman Whoops. ¿Tiene $(( ... ))? Si es así, mi respuesta aún debería ser materialmente correcta, solo necesito agregar algunas citas adicionales.
godlygeek
es tu respuesta: ve a descubrirlo.
Glenn Jackman
Parece que sí, así que mi versión actualizada debería ser suficiente. Sin embargo, no tengo carrera para probarlo, así que avíseme si me perdí algo más.
godlygeek
Intenté: check_if_number 1.2y la función volvió: dash: 3: arithmetic expression: expecting EOF: "1.2"
John1024
0

Quizás con expr?

if expr match "$1" '^\([0-9]\+\)$' > /dev/null; then
  echo "integer"
else 
  echo "non-integer"
fi
conductor de acero
fuente
ni matchtampoco \+son POSIX. También diría que 0 no es un número. Tú quieresexpr "x$1" : 'x[0-9]\{1,\}$'
Stéphane Chazelas
0

En el sistema POSIX, puede usar expr :

$ a=a
$ expr "$a" - 0 >/dev/null 2>&1
$ [ "$?" -lt 2 ] && echo Integer || echo Not Integer
Cuonglm
fuente
Dirá que 0 no es un entero (y digamos -12 es lo que la solución bash del OP habría rechazado). Algunas exprimplementaciones dirán que 9999999999999999999 no es un número entero. POSIX no garantiza que esto funcione. En la práctica, al menos en un sistema GNU, dirá que "longitud" es un número entero.
Stéphane Chazelas
En mi prueba, funciona al menos en Debian y OSX. Dice entero para 0. Posix asegura que $ a debe ser una expresión válida (entero) para expr do aritmética.
cuonglm
Oh sí, lo siento, había pasado por alto tu prueba por $? <2. Todavía expr 9999999999999999999 + 0me da un estado de salida 3 expr -12 + 0y expr length + 0me da un estado de salida 0 con GNU expr ( + stringobliga stringa ser considerado como una cadena con GNU expr. expr "$a" - 0Funcionaría mejor).
Stéphane Chazelas
@ StéphaneChazelas: Oh, sí, actualicé mi respuesta. Creo que -12es un número entero válido, y 9999999999999999999dio un desbordamiento.
cuonglm
0

Aquí hay una función simple que usa el mismo método que la respuesta de muru :

IsInteger()      # usage: IsInteger string
{               #  returns: flag
        [ "$1" -eq "$1" ] 2> /dev/null
}

Ejemplo:

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"

Salida:

'2a3' isn't an integer
'23' is an integer
agc
fuente