894 Stimmen

Wie kann ich in der Bash testen, ob eine Variable eine Zahl ist?

Ich kann einfach nicht herausfinden, wie ich sicherstellen kann, dass ein an mein Skript übergebenes Argument eine Zahl ist oder nicht.

Alles, was ich tun möchte, ist so etwas wie das hier:

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

Gibt es Hilfe?

21 Stimmen

Nebenbei bemerkt - die test && echo "foo" && exit 0 || echo "bar" && exit 1 Ansatz, den Sie verwenden, kann einige unbeabsichtigte Nebeneffekte haben -- wenn das Echo fehlschlägt (vielleicht ist die Ausgabe an einen geschlossenen FD), wird die exit 0 wird übersprungen, und der Code wird dann versuchen echo "bar" . Scheitert sie auch daran, wird die && wird fehlschlagen, und es wird nicht einmal ausgeführt exit 1 ! Mit aktuellen if Erklärungen und nicht && / || ist weniger anfällig für unerwartete Nebenwirkungen.

0 Stimmen

@CharlesDuffy Das ist die Art von wirklich cleverem Denken, zu dem die meisten Leute nur kommen, wenn sie haarige Bugs aufspüren müssen...! Ich hätte nie gedacht, dass Echo einen Fehler zurückgeben könnte.

13 Stimmen

Ich bin zwar etwas spät dran, aber ich weiß um die Gefahren, über die Charles geschrieben hat, da ich sie vor einiger Zeit auch durchmachen musste. Hier ist also eine 100 % narrensichere (und gut lesbare) Zeile für Sie: [[ $1 =~ "^[0-9]+$" ]] && { echo "number"; exit 0; } || { echo "not a number"; exit 1; } Die geschweiften Klammern zeigen an, dass die Dinge NICHT in einer Subshell ausgeführt werden sollen (was bei () stattdessen Klammern verwenden). Vorbehalt: Niemals das letzte Semikolon vergessen . Andernfalls könnten Sie bash um die hässlichsten (und sinnlosesten) Fehlermeldungen auszugeben...

11voto

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

${i//[0-9]} ersetzt eine beliebige Ziffer im Wert von $i mit einer leeren Zeichenkette, siehe man -P 'less +/parameter\/' bash . -z prüft, ob die resultierende Zeichenkette die Länge Null hat.

wenn Sie auch den Fall ausschließen wollen, dass $i leer ist, können Sie eine der folgenden Konstruktionen verwenden:

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

10voto

Joseph Shih Punkte 1114

Dies kann erreicht werden durch die Verwendung von grep um festzustellen, ob die betreffende Variable mit einem erweiterten regulären Ausdruck übereinstimmt.

Test Ganzzahl 1120 :

yournumber=1120
if echo "$yournumber" | grep -qE '^[0-9]+$'; then
    echo "Valid number."
else
    echo "Error: not a number."
fi

Ausgabe: Valid number.

Test nicht-ganzzahlig 1120a :

yournumber=1120a
if echo "$yournumber" | grep -qE '^[0-9]+$'; then
    echo "Valid number."
else
    echo "Error: not a number."
fi

Ausgabe: Error: not a number.


Erläuterung

  • Le site grep die -E erlaubt uns die Verwendung von erweiterten regulären Ausdrücken '^[0-9]+$' . Dieser reguläre Ausdruck bedeutet, dass die Variable nur [] enthalten die Zahlen 0-9 null bis neun aus dem ^ Anfang zum $ Ende der Variable und sollte mindestens + ein Zeichen.
  • Le site grep die -q Der Quiet-Schalter schaltet alle Ausgaben aus, unabhängig davon, ob er etwas findet oder nicht.
  • if prüft den Exit-Status von grep . Status "Beenden 0 bedeutet Erfolg, alles darüber hinaus bedeutet einen Fehler. Die Website grep hat einen Exit-Status von 0 wenn es eine Übereinstimmung findet und 1 wenn es nicht der Fall ist;

Zusammenfassend lässt sich also sagen, dass in der if Test, wir echo die Variable $yournumber y | leiten Sie es an grep die mit dem -q Schalter entspricht stillschweigend dem -E erweiterter regulärer Ausdruck '^[0-9]+$' Ausdruck. Der Exit-Status von grep wird sein 0 wenn grep erfolgreich eine Übereinstimmung gefunden und 1 wenn es nicht so wäre. Wenn es gelingt, übereinzustimmen, werden wir echo "Valid number." . Wenn es nicht übereinstimmt, werden wir echo "Error: not a number." .


Für Schwimmer oder Doppelgänger

Wir können den regulären Ausdruck einfach von '^[0-9]+$' a '^[0-9]*\.?[0-9]+$' für Floats oder Doppelgänger.

Test Schwimmer 1120.01 :

yournumber=1120.01
if echo "$yournumber" | grep -qE '^[0-9]*\.?[0-9]+$'; then
    echo "Valid number."
else
    echo "Error: not a number."
fi

Ausgabe: Valid number.

Test Schwimmer 11.20.01 :

yournumber=11.20.01
if echo "$yournumber" | grep -qE '^[0-9]*\.?[0-9]+$'; then
    echo "Valid number."
else
    echo "Error: not a number."
fi

Ausgabe: Error: not a number.


Für Negative

Um negative ganze Zahlen zuzulassen, ändern Sie einfach den regulären Ausdruck von '^[0-9]+$' a '^\-?[0-9]+$' .

Um negative Floats oder Doubles zuzulassen, ändern Sie einfach den regulären Ausdruck von '^[0-9]*\.?[0-9]+$' a '^\-?[0-9]*\.?[0-9]+$' .

10voto

Sammitch Punkte 27098

Eine alte Frage, aber ich wollte nur meine Lösung anbringen. Diese erfordert keine merkwürdigen Shell-Tricks oder verlässt sich auf etwas, das es nicht schon immer gegeben hat.

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

Im Grunde werden einfach alle Ziffern aus der Eingabe entfernt, und wenn eine Zeichenkette mit einer Länge ungleich Null übrig bleibt, war es keine Zahl.

7voto

overflowed Punkte 95

Ich würde dies versuchen:

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

Hinweis: Dabei werden nan und inf als Zahl erkannt.

7voto

karttu Punkte 91

Ich kann noch keinen Kommentar abgeben, also füge ich meine eigene Antwort hinzu, die eine Erweiterung der Antwort von Glenn Jackman ist, indem ich den Bash-Mustervergleich verwende.

Ursprünglich ging es mir darum, Zahlen zu identifizieren und zwischen Ganzzahlen und Gleitkommazahlen zu unterscheiden. Die Funktion Definitionen abgeleitet, um:

function isInteger() {
    [[ ${1} == ?(-)+([0-9]) ]]
}

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

Ich habe Unit-Tests (mit shUnit2) verwendet, um zu überprüfen, ob meine Muster wie vorgesehen funktionieren:

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

}

Anmerkungen: Das isFloat-Muster kann so modifiziert werden, dass es toleranter gegenüber Dezimalstellen ist ( @(.,) ) und das Symbol E ( @(Ee) ). Meine Unit-Tests testen nur Werte, die entweder Integer oder Float sind, aber keine ungültigen Eingaben.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X