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...

57voto

mrucci Punkte 4192

Dies prüft, ob eine Zahl eine nicht-negative ganze Zahl ist. Es ist Shell-unabhängig (d.h. ohne Bashismen) und verwendet nur Shell-Build-Ins:

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

In einer früheren Version dieser Antwort wurde vorgeschlagen:

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

aber das ist FALSCH da es jede Zeichenkette akzeptiert, die mit einer Ziffer beginnt, wie jilles schlug vor .

27voto

pixelbeat Punkte 28985

Ich bin überrascht über die Lösungen, die Zahlenformate direkt in der Shell analysieren. Die Shell ist dafür nicht gut geeignet, da sie eine DSL zur Steuerung von Dateien und Prozessen ist. Es gibt reichlich Zahlen-Parser ein wenig weiter unten, zum Beispiel:

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
}

Ändern Sie "%f" in das von Ihnen gewünschte Format.

22voto

Sergio Abreu Punkte 2326

Ich habe mir die Antworten angesehen und... festgestellt, dass niemand an FLOAT-Zahlen (mit Punkt) gedacht hat!

Die Verwendung von grep ist ebenfalls sehr hilfreich.
-E bedeutet erweiterte Regexp
-q bedeutet Ruhe (kein Echo)
-qE ist die Kombination aus beidem.

Zum Testen direkt in der Befehlszeile:

$ 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

Verwendung in einem Bash-Skript:

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

Um JUST Ganzzahlen abzugleichen, verwenden Sie dies:

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

14voto

triple_r Punkte 1002

Nur ein Nachtrag zu @mary. Aber weil ich nicht genug Ansehen habe, konnte ich dies nicht als Kommentar zu diesem Beitrag posten. Wie auch immer, hier ist, was ich verwendet habe:

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

Die Funktion gibt eine "1" zurück, wenn das Argument eine Zahl ist, andernfalls eine "0". Dies funktioniert sowohl für Ganzzahlen als auch für Fließkommazahlen. Die Verwendung ist etwa so:

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

11voto

Hachi Punkte 3197

Für mein Problem musste ich nur sicherstellen, dass ein Benutzer nicht versehentlich einen Text eingibt, daher habe ich versucht, es einfach und lesbar zu halten

isNumber() {
    (( $1 )) 2>/dev/null
}

Laut der Manpage macht das ziemlich genau das, was ich will

Ist der Wert des Ausdrucks ungleich Null, ist der Rückgabewert 0

Um unangenehme Fehlermeldungen für Strings zu vermeiden, die "Zahlen sein könnten", ignoriere ich die Fehlerausgabe

$ (( 2s ))
bash: ((: 2s: value too great for base (error token is "2s")

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