/ bin / dash: controlla se $ 1 è un numero


12

Quale sarebbe il modo migliore per verificare se $ 1 è un numero intero in / bin / dash?

In bash, potrei fare:

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

Ma questo non sembra conforme a POSIX e il trattino non lo supporta

Risposte:


12

I seguenti rilevano numeri interi, positivi o negativi, e funzionano sotto dashe sono POSIX:

opzione 1

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

opzione 2

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

Oppure, con un piccolo uso del :comando (nop):

! case ${1#[+-]} in *[!0-9]*) :;; ?*) ! :;; esac && echo Integer

5
Cosa succede se la stringa contiene nuove righe? foo\n123\nbarnon è un numero intero, ma supererebbe questo test.
godlygeek,

3
La versione grep, cioè. La versione del case sembra corretta.
godlygeek,

5

Sia dash, bash, ksh, zsh, POSIX sh, o posh( "una reimplementazione del guscio Bourne" sh ); il casecostrutto è il più ampiamente disponibile e affidabile:

case $1 in (*[!0-9]*|"") false ;; (*) true ;; esac

Hai provato questo sotto dash? Funziona per me sotto bashma non dash.
Giovanni 1024,

Sì, l'ho provato anche sul mio sistema con dash; per interrogare il risultato che ho aggiunto echo $?dopo il comando case.
Janis,

Ho fatto lo stesso (Debian stable) ma nessuna gioia. Per un esempio completo che funziona per me sotto il mio trattino, vedere la mia opzione 2 .
Giovanni 1024,

Hmm, non ho nessuna shell bourne originale disponibile per il test. I documenti che ho esaminato su "caratteristiche [in ksh] non nella shell bourne" almeno non lo menzionano, quindi presumo che fosse lì. No? - Quindi omettere la parentesi iniziale. - OTOH, posh("una reimplementazione della shell Bourne"), tuttavia, non ha problemi con questa soluzione.
Janis,

1
@mikeserv; Ci sono diversi motivi per cui uso sempre le parentesi corrispondenti case; un motivo è il bug che descrivi, un altro che negli editor che hanno funzionalità che si basano sulla parentesi corrispondente (vim) offre un supporto molto migliore, e non ultimo trovo che sia meglio leggibile personalmente averli corrispondenti. - WRT poshessendo POSIX; beh, la citazione dalla pagina man che ho dato ha suggerito qualcos'altro, ma comunque non si può fare affidamento su tali dichiarazioni informali. Il vecchio bourne shell non è più così significativo ora che siamo nell'era POSIX.
Janis,

1

Puoi usare il -eqtest sulla stringa, con se stesso:

$ 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 il messaggio di errore è un problema, reindirizzare l'output dell'errore a /dev/null:

$ dash -c 'a="0xa"; [ "$a" -eq "$a" ] 2>/dev/null|| echo no'
no

1
Direbbe anche che " 023 "è un numero. Si noti che funziona con trattino, ma non con tutte le altre shell POSIX poiché il comportamento non è specificato se gli operandi sono numeri decimali di nota. Ad esempio con ksh, direbbe che SHLVLo 1+1è un numero.
Stéphane Chazelas,

0

Prova a usarlo come espansione aritmetica e vedi se funziona. In realtà, devi essere un po 'più rigoroso di quello, perché le espansioni aritmetiche ignorerebbero gli spazi iniziali e finali, ad esempio. Quindi esegui un'espansione aritmetica e assicurati che il risultato espanso corrisponda esattamente alla variabile originale.

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

Questo accetterebbe anche numeri negativi - se vuoi davvero escluderli, aggiungi un ulteriore controllo per $((${1} >= 0)).


1
il trattino non ha[[
glenn jackman,

@glennjackman Whoops. Ha $(( ... ))? In tal caso, la mia risposta dovrebbe essere ancora materialmente corretta, ho solo bisogno di aggiungere alcune citazioni extra.
godlygeek,

è la tua risposta: vai a scoprirlo.
Glenn Jackman,

Sembra così, quindi la mia versione aggiornata dovrebbe fare il trucco. Non ho un trattino per provarlo, quindi fammi sapere se ho perso qualcos'altro.
godlygeek,

Ho provato: check_if_number 1.2e la funzione è tornata: dash: 3: arithmetic expression: expecting EOF: "1.2"
John1024

0

Forse con expr?

if expr match "$1" '^\([0-9]\+\)$' > /dev/null; then
  echo "integer"
else 
  echo "non-integer"
fi

match\+POSIX. Direbbe anche che 0 non è un numero. Voleteexpr "x$1" : 'x[0-9]\{1,\}$'
Stéphane Chazelas il

0

Nel sistema POSIX, è possibile utilizzare expr :

$ a=a
$ expr "$a" - 0 >/dev/null 2>&1
$ [ "$?" -lt 2 ] && echo Integer || echo Not Integer

Dirà che 0 non è un numero intero (e dire -12 è che la soluzione bash dell'OP avrebbe rifiutato). Alcune exprimplementazioni diranno che 9999999999999999999 non è un numero intero. POSIX non offre alcuna garanzia sul funzionamento. In pratica, almeno su un sistema GNU, dirà che "lunghezza" è un numero intero.
Stéphane Chazelas,

Nel mio test, funziona almeno in Debian e OSX. Indica numero intero per 0. Posix garantisce che $ a deve essere un'espressione valida (numero intero) per l'espressione aritmetica.
cuonglm,

Oh sì, scusa, avevo trascurato il tuo test per $? <2. expr 9999999999999999999 + 0Mi dà ancora uno stato di uscita 3 expr -12 + 0e expr length + 0mi dà uno stato di uscita 0 con GNU expr (le + stringforze stringda considerare come una stringa con GNU expr. expr "$a" - 0Funzionerebbero meglio).
Stéphane Chazelas,

@ StéphaneChazelas: Oh, sì, ho aggiornato la mia risposta. Penso che -12sia un numero intero valido e ha 9999999999999999999dato un overflow.
cuonglm,

0

Ecco una semplice funzione che utilizza lo stesso metodo della risposta di Muru :

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

Esempio:

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"

Produzione:

'2a3' isn't an integer
'23' is an integer
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.