/ bin / dash: Überprüfe, ob $ 1 eine Zahl ist

12

Was wäre der beste Weg, um zu überprüfen, ob $ 1 eine Ganzzahl in / bin / dash ist?

In Bash könnte ich tun:

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

Dies scheint jedoch nicht POSIX-konform zu sein, und Dash unterstützt dies nicht

Martin Vegter
quelle

Antworten:

12

Die folgenden Funktionen erkennen positive oder negative Ganzzahlen und arbeiten unter dashund sind POSIX:

Option 1

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

Option 2

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

Oder mit ein wenig Gebrauch des :(nop) -Befehls:

! case ${1#[+-]} in *[!0-9]*) :;; ?*) ! :;; esac && echo Integer
John1024
quelle
5
Was ist, wenn die Zeichenfolge Zeilenumbrüche enthält? foo\n123\nbarist keine ganze Zahl, würde aber diesen Test bestehen.
Godlygeek
3
Die grep-Version also. Die Gehäuseversion sieht korrekt aus.
Godlygeek
5

Ob dash, bash, ksh, zsh, POSIX shoder posh( "a Reimplementation der Bourne - Shell" sh ); Das caseKonstrukt ist das am weitesten verbreitete und zuverlässigste:

case $1 in (*[!0-9]*|"") false ;; (*) true ;; esac
Janis
quelle
Hast du das unter getestet dash? Es funktioniert bei mir unter bashaber nicht dash.
John1024
Ja, ich habe es auf meinem System auch mit getestet dash; Um das Ergebnis abzufragen, habe ich echo $?nach dem case-Befehl hinzugefügt .
Janis
Ich habe dasselbe gemacht (Debian-Stall), aber keine Freude. Ein vollständiges Beispiel, das für mich unter meinem Gedankenstrich funktioniert, finden Sie unter Option 2 .
John1024
Hmm, ich habe keine original Bourneshell zum testen. Die Dokumente, die ich über "Features [in ksh] nicht in Borowski-Shell" untersucht habe, erwähnen es zumindest nicht, also nehme ich an, dass es dort war. Nein? - Dann lassen Sie die führende Klammer weg. - OTOH posh("eine Neuimplementierung der Bourne-Shell") hat mit dieser Lösung allerdings auch kein Problem.
Janis
1
@mikeserv; Es gibt mehrere Gründe, warum ich immer passende Klammern in verwende case. Ein Grund ist der Fehler, den Sie beschreiben, ein anderer, der in Editoren mit Funktionen, die auf übereinstimmende Klammern (vim) angewiesen sind, eine viel bessere Unterstützung bietet, und nicht zuletzt finde ich es persönlich besser lesbar, wenn sie übereinstimmen. - WRT poshist POSIX; Nun, das Zitat aus der Manpage, das ich gegeben habe, deutete auf etwas anderes hin, aber man kann sich sowieso nicht auf solche informellen Aussagen verlassen, denke ich. Die alte Borowski-Shell ist sowieso nicht mehr so ​​bedeutend, seit wir uns in der POSIX-Ära befinden.
Janis
1

Sie können den -eqTest für die Zeichenfolge mit sich selbst verwenden:

$ 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

Wenn die Fehlermeldung ein Problem darstellt, leiten Sie die Fehlerausgabe weiter an /dev/null:

$ dash -c 'a="0xa"; [ "$a" -eq "$a" ] 2>/dev/null|| echo no'
no
muru
quelle
1
Es würde auch sagen, dass " 023 "das eine Zahl ist. Beachten Sie, dass dies mit Bindestrich funktioniert, jedoch nicht mit allen anderen POSIX-Shells, da das Verhalten nicht spezifiziert ist, wenn die Operanden Dezimalzahlen sind. Zum Beispiel mit ksh würde es sagen, dass SHLVLoder 1+1eine Zahl ist.
Stéphane Chazelas
0

Versuchen Sie, es als arithmetische Erweiterung zu verwenden, und prüfen Sie, ob es funktioniert. Eigentlich muss man etwas strenger sein, weil arithmetische Erweiterungen zum Beispiel führende und nachfolgende Leerzeichen ignorieren würden. Führen Sie also eine arithmetische Erweiterung durch und stellen Sie sicher, dass das erweiterte Ergebnis genau mit der ursprünglichen Variablen übereinstimmt.

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

Dies würde auch negative Zahlen akzeptieren - wenn Sie sie wirklich ausschließen möchten, fügen Sie einen zusätzlichen Scheck für hinzu $((${1} >= 0)).

godlygeek
quelle
1
Dash nicht haben[[
Glenn Jackman
@glennjackman Hoppla. Hat es $(( ... ))? Wenn ja, sollte meine Antwort immer noch sachlich korrekt sein, ich muss nur ein zusätzliches Zitat hinzufügen.
Godlygeek
Das ist deine Antwort: finde es heraus.
Glenn Jackman
Sieht so aus, als würde meine aktualisierte Version den Trick machen. Ich habe aber keine Chance, es auszuprobieren - lassen Sie es mich wissen, wenn ich etwas anderes verpasst habe.
Godlygeek
Ich habe versucht: check_if_number 1.2und die Funktion zurückgegeben: dash: 3: arithmetic expression: expecting EOF: "1.2"
John1024
0

Vielleicht mit expr?

if expr match "$1" '^\([0-9]\+\)$' > /dev/null; then
  echo "integer"
else 
  echo "non-integer"
fi
Stahlfahrer
quelle
weder matchnoch \+sind POSIX. Es würde auch sagen, dass 0 keine Zahl ist. Sie wollenexpr "x$1" : 'x[0-9]\{1,\}$'
Stéphane Chazelas
0

Im POSIX-System können Sie expr verwenden :

$ a=a
$ expr "$a" - 0 >/dev/null 2>&1
$ [ "$?" -lt 2 ] && echo Integer || echo Not Integer
cuonglm
quelle
Es wird gesagt, dass 0 keine ganze Zahl ist (und sagen wir -12, was die Bash-Lösung des OP abgelehnt hätte). Einige exprImplementierungen werden sagen, dass 9999999999999999999 keine ganze Zahl ist. POSIX gibt keine Garantie, dass dies funktioniert. In der Praxis wird zumindest auf einem GNU-System gesagt, dass "Länge" eine ganze Zahl ist.
Stéphane Chazelas
In meinem Test funktioniert es zumindest in Debian und OSX. Es wird eine Ganzzahl für 0 angegeben. Posix stellt sicher, dass $ a ein gültiger Ausdruck (Ganzzahl) für Ausdrucksarithmetik sein muss.
Cuonglm
Oh ja, sorry, ich hatte deinen Test für $ übersehen? <2. Noch expr 9999999999999999999 + 0gibt mir ein 3 Exit - Status und expr -12 + 0und expr length + 0geben Sie mir eine 0 Exit - Status mit GNU ausdr ( + stringKräfte stringals String mit GNU berücksichtigt werden expr. expr "$a" - 0Besser funktionieren würde).
Stéphane Chazelas
@ StéphaneChazelas: Oh ja, meine Antwort wurde aktualisiert. Ich denke, -12ist eine gültige Ganzzahl und 9999999999999999999gab einen Überlauf.
Cuonglm
0

Hier ist eine einfache Funktion, die dieselbe Methode wie die Antwort von muru verwendet :

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

Beispiel:

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"

Ausgabe:

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