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

5voto

ultrasawblade Punkte 105

http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_04_03.html

Sie können auch die Zeichenklassen der Bash verwenden.

if [[ $VAR = *[[:digit:]]* ]]; then
 echo "$VAR is numeric"
else
 echo "$VAR is not numeric"
fi

Zahlen enthalten Leerzeichen, den Dezimalpunkt und "e" oder "E" für Gleitkomma.

Wenn Sie jedoch eine Hex-Zahl im C-Stil angeben, z.B. "0xffff" oder "0XFFFF", gibt [[:digit:]] true zurück. Ein bisschen eine Falle hier, Bash können Sie etwas wie "0xAZ00" zu tun und immer noch zählen es als eine Ziffer (ist dies nicht von einigen seltsamen Eigenart der GCC-Compiler, die Sie 0x Notation für andere Basen als 16 verwenden können???)

Sie sollten auf "0x" oder "0X" testen, bevor Sie prüfen, ob es sich um eine numerische Zahl handelt, wenn Ihre Eingabe völlig unzuverlässig ist, es sei denn, Sie wollen Hex-Zahlen akzeptieren. Das würde erreicht werden durch:

if [[ ${VARIABLE:1:2} = "0x" ]] || [[ ${VARIABLE:1:2} = "0X" ]]; then echo "$VAR is not numeric"; fi

5voto

Ich verwende printf, wie bereits in anderen Antworten erwähnt. Wenn Sie die Formatzeichenfolge "%f" oder "%i" eingeben, übernimmt printf die Prüfung für Sie. Es ist einfacher, als die Prüfungen neu zu erfinden, die Syntax ist einfach und kurz und printf ist allgegenwärtig. Meiner Meinung nach ist es also eine gute Wahl - Sie können die folgende Idee auch verwenden, um eine Reihe von Dingen zu überprüfen, es ist nicht nur nützlich für die Überprüfung von Zahlen.

declare  -r CHECK_FLOAT="%f"  
declare  -r CHECK_INTEGER="%i"  

 ## <arg 1> Number - Number to check  
 ## <arg 2> String - Number type to check  
 ## <arg 3> String - Error message  
function check_number() { 
  local NUMBER="${1}" 
  local NUMBER_TYPE="${2}" 
  local ERROR_MESG="${3}"
  local -i PASS=1 
  local -i FAIL=0   
  case "${NUMBER_TYPE}" in 
    "${CHECK_FLOAT}") 
        if ((! $(printf "${CHECK_FLOAT}" "${NUMBER}" &>/dev/random;echo $?))); then 
           echo "${PASS}"
        else 
           echo "${ERROR_MESG}" 1>&2
           echo "${FAIL}"
        fi 
        ;;                 
    "${CHECK_INTEGER}") 
        if ((! $(printf "${CHECK_INTEGER}" "${NUMBER}" &>/dev/random;echo $?))); then 
           echo "${PASS}"
        else 
           echo "${ERROR_MESG}" 1>&2
           echo "${FAIL}"
        fi 
        ;;                 
                     *) 
        echo "Invalid number type format: ${NUMBER_TYPE} to check_number()." 1>&2
        echo "${FAIL}"
        ;;                 
   esac
} 

>$ var=45

>$ (($(check_number $var "${CHECK_INTEGER}" "Error: Found $var - An integer is required."))) && { echo "$var+5" | bc; }

4voto

user3895088 Punkte 55

Mir gefällt die Antwort von Alberto Zaccagni.

if [ "$var" -eq "$var" ] 2>/dev/null; then

Wichtige Voraussetzungen: - keine Subshells werden erzeugt - keine RE-Parser aufgerufen - die meisten Shell-Anwendungen verwenden keine reellen Zahlen

Aber wenn $var komplex ist (z.B. ein assoziativer Array-Zugriff), und wenn die Zahl eine nicht-negative ganze Zahl ist (die meisten Anwendungsfälle), dann ist dies vielleicht effizienter?

if [ "$var" -ge 0 ] 2> /dev/null; then ..

2voto

user28490 Punkte 1007

Um negative Zahlen zu erfassen:

if [[ $1 == ?(-)+([0-9.]) ]]
    then
    echo number
else
    echo not a number
fi

2voto

Idriss Neumann Punkte 3636

Sie könnten auch "let" wie folgt verwenden:

[ ~]$ var=1
[ ~]$ let $var && echo "It's a number" || echo "It's not a number"
It\'s a number
[ ~]$ var=01
[ ~]$ let $var && echo "It's a number" || echo "It's not a number"
It\'s a number
[ ~]$ var=toto
[ ~]$ let $var && echo "It's a number" || echo "It's not a number"
It\'s not a number
[ ~]$ 

Aber ich benutze lieber den "=~" Bash 3+ Operator wie einige Antworten in diesem Thread.

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