Ich kann einfach nicht herausfinden, wie ich sicherstellen kann, dass ein Argument, das an mein Skript übergeben wird, eine Zahl ist oder nicht.
Alles was ich tun möchte ist so etwas:
test *isnumber* $1 && VAR=$1 || echo "need a number"
Irgendeine Hilfe?
Ein Ansatz besteht darin, einen regulären Ausdruck zu verwenden:
re='^[0-9]+$'
if ! [[ $yournumber =~ $re ]] ; then
echo "error: Not a number" >&2; exit 1
fi
Wenn der Wert nicht unbedingt eine ganze Zahl ist, sollten Sie die Regex entsprechend ändern. zum Beispiel:
^[0-9]+([.][0-9]+)?$
... oder um Zahlen mit einem Zeichen zu behandeln:
^[+-]?[0-9]+([.][0-9]+)?$
Ohne Basismen (funktioniert auch im System V sh),
case $string in
''|*[!0-9]*) echo bad ;;
*) echo good ;;
esac
Dies lehnt leere Zeichenfolgen und Zeichenfolgen ab, die Nicht-Ziffern enthalten, und akzeptiert alles andere.
Negative oder Fließkommazahlen erfordern zusätzliche Arbeit. Eine Idee ist, -
/.
im ersten "schlechten" Muster auszuschließen und weitere "schlechte" Muster hinzuzufügen, die die unangemessene Verwendung enthalten (?*-*
/*.*.*
)
Die folgende Lösung kann auch in einfachen Shells wie Bourne verwendet werden, ohne dass reguläre Ausdrücke erforderlich sind. Grundsätzlich führen alle numerischen Wertevaluierungsoperationen, die Nichtzahlen verwenden, zu einem Fehler, der implizit in Shell als falsch betrachtet wird:
"$var" -eq "$var"
wie in:
#!/bin/bash
var=a
if [ -n "$var" ] && [ "$var" -eq "$var" ] 2>/dev/null; then
echo number
else
echo not a number
fi
Sie können auch auf $ testen? der Rückkehrcode der Operation, der expliziter ist:
[ -n "$var" ] && ["$var" -eq "$var"] 2>/dev/null
if [ $? -ne 0 ]; then
echo $var is not number
fi
Die Umleitung des Standardfehlers dient dazu, die Meldung "Integer-Ausdruck erwartet" auszublenden, die von bash ausgegeben wird, falls keine Zahl vorhanden ist.
VORBEHALTE(dank der Kommentare unten):
[[ ]]
anstelle von [ ]
wird immer zu true
ausgewertet.true
.bash: [[: 1 a: syntax error in expression (error token is "a")
.bash: [[: i: expression recursion level exceeded (error token is "i")
.Dies prüft, ob eine Zahl eine nicht negative ganze Zahl ist und sowohl von der Shell unabhängig ist (d. H. Ohne Bashismen), als nur die integrierten Shell-Ins:
[ -z "${num##[0-9]*}" ] && echo "is a number" || echo "is not a number";
ABER IS FALSCH.
Wie jilles kommentiert und in seine Antwort vorgeschlagen ist dies der richtige Weg, dies mit Shell-Mustern zu tun.
[ ! -z "${num##*[!0-9]*}" ] && echo "is a number" || echo "is not a number";
Niemand hat vorgeschlagen bash erweiterte Musterübereinstimmung :
[[ $1 == ?(-)+([0-9]) ]] && echo "$1 is an integer"
Ich bin überrascht, dass die Lösungen Zahlenformate direkt in Shell analysieren Shell eignet sich nicht dafür, da es sich um eine DSL-Steuerung für Dateien und Prozesse handelt
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 gewünschte Format.
Ich sah mir die Antworten an und stellte fest, dass niemand an FLOAT-Nummern (mit Punkt) dachte!
Die Verwendung von grep ist auch großartig.
- E bedeutet erweiterter Ausdruck
- q bedeutet leise (kein Echo)
- qE ist die Kombination aus beiden.
So testen Sie 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
Verwenden 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 zu finden, verwenden Sie Folgendes:
# change check line to:
check=`echo "$1" | grep -E ^\-?[0-9]+$`
Nur ein Anschluss an @mary. Aber da ich nicht genügend Vertreter 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 "1" zurück, wenn das Argument eine Zahl ist, andernfalls "0". Dies funktioniert sowohl für Ganzzahlen als auch für Floats. Verwendung ist so etwas wie:
n=-2.05e+07
res=`isnum "$n"`
if [ "$res" == "1" ]; then
echo "$n is a number"
else
echo "$n is not a number"
fi
http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_04_03.html
Sie können auch die Zeichenklassen von bash verwenden.
if [[ $VAR = *[[:digit:]]* ]]; then
echo "$VAR is numeric"
else
echo "$VAR is not numeric"
fi
Numerik enthält Leerzeichen, den Dezimalpunkt und "e" oder "E" für Fließkommazahl.
Wenn Sie jedoch eine Hexadezimalzahl im C-Stil angeben, d. H. "0xffff" oder "0XFFFF", gibt [[: digit:]] "true" zurück. Ein bisschen Trap hier. Mit bash können Sie so etwas wie "0xAZ00" tun und es immer noch als eine Ziffer zählen (ist dies nicht ein Teil der komischen GCC-Compiler, bei dem Sie die 0x-Notation für andere Basen als 16 verwenden können ??? )
Möglicherweise möchten Sie vor dem Test auf "0x" oder "0X" testen, ob es sich um eine numerische Zahl handelt, wenn Ihre Eingabe vollständig nicht vertrauenswürdig ist, es sei denn, Sie möchten Hexadezimalzahlen akzeptieren. Das würde erreicht werden durch:
if [[ ${VARIABLE:1:2} = "0x" ]] || [[ ${VARIABLE:1:2} = "0X" ]]; then echo "$VAR is not numeric"; fi
Alte Frage, aber ich wollte nur meine Lösung angehen. Dieses erfordert keine seltsamen Shell-Tricks oder verlässt sich auf etwas, das es noch nie 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 nur alle Ziffern aus der Eingabe entfernt, und wenn Sie eine Zeichenfolge mit einer Länge ungleich Null haben, ist diese keine Zahl.
test -z "${i//[0-9]}" && echo digits || echo no no no
${i//[0-9]}
ersetzt jede Ziffer im Wert von $i
durch eine leere Zeichenfolge, siehe man -P 'less +/parameter\/' bash
. -z
prüft, ob die resultierende Zeichenfolge null ist.
wenn Sie auch den Fall ausschließen möchten, wenn $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
[[ $1 =~ ^-?[0-9]+$ ]] && echo "number"
Vergessen Sie nicht, dass -
negative Zahlen enthält!
Ich kann noch nicht kommentieren, also füge ich meine eigene Antwort hinzu, die eine Erweiterung der Antwort von glenn jackman mit dem bash-Pattern-Matching ist.
Mein ursprüngliches Bedürfnis bestand darin, Zahlen zu identifizieren und ganze Zahlen und Floats zu unterscheiden. Die Funktionsdefinitionen abgezogen an:
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 bestätigen, dass meine Muster wie erwartet 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
}
Hinweise: Das isFloat-Muster kann geändert werden, um den Dezimalpunkt (@(.,)
) und das E-Symbol (@(Ee)
) toleranter zu machen. Mein Unit-Test testet nur Werte, die entweder eine Ganzzahl oder ein Gleitkomma sind, jedoch keine ungültigen Eingaben.
Ich würde das versuchen:
printf "%g" "$var" &> /dev/null
if [[ $? == 0 ]] ; then
echo "$var is a number."
else
echo "$var is not a number."
fi
Hinweis: Dies erkennt nan und inf als Zahl.
Am einfachsten prüfen Sie, ob es nicht-numerische Zeichen enthält. Sie ersetzen alle Ziffern durch nichts und prüfen auf Länge. Wenn es Länge gibt, ist es keine Zahl.
if [[ ! -n ${input//[0-9]/} ]]; then
echo "Input Is A Number"
fi
Eine eindeutige Antwort wurde bereits von @charles Dufy und anderen gegeben. Eine reine Bash-Lösung würde Folgendes verwenden:
string="-12,345"
if [[ "$string" =~ ^-?[0-9]+[.,]?[0-9]*$ ]]
then
echo $string is a number
else
echo $string is not a number
fi
Bei reellen Zahlen ist es jedoch nicht zwingend, vor dem radix-Punkt eine Zahl zu haben.
Um eine gründlichere Unterstützung für Floating-Nummern und wissenschaftliche Notationen bereitzustellen (viele Programme in C/Fortran oder werden auf diese Weise Float exportiert), wäre eine sinnvolle Ergänzung dieser Zeile die folgende:
string="1.2345E-67"
if [[ "$string" =~ ^-?[0-9]*[.,]?[0-9]*[eE]?-?[0-9]+$ ]]
then
echo $string is a number
else
echo $string is not a number
fi
Wenn Sie nach einem bestimmten Typ suchen, führt dies zu einer Möglichkeit, die Nummernarten zu unterscheiden:
string="-12,345"
if [[ "$string" =~ ^-?[0-9]+$ ]]
then
echo $string is an integer
Elif [[ "$string" =~ ^-?[0-9]*[.,]?[0-9]*$ ]]
then
echo $string is a float
Elif [[ "$string" =~ ^-?[0-9]*[.,]?[0-9]*[eE]-?[0-9]+$ ]]
then
echo $string is a scientific number
else
echo $string is not a number
fi
Hinweis: Wir können die syntaktischen Anforderungen für die Dezimal- und wissenschaftliche Notation auflisten, wobei Kommas als Radix-Punkt sowie "." Zulässig ist. Wir würden dann behaupten, dass es nur einen solchen Radixpunkt geben muss. [Ee] Float kann zwei Vorzeichen enthalten. Ich habe ein paar weitere Regeln aus Aulu's Arbeit gelernt und mit schlechten Zeichenketten wie '' '-' '-E-1' '0-0' getestet. Hier sind meine Tools für Regex/Teilstring/Ausdruck, die sich zu halten scheinen:
parse_num() {
local r=`expr "$1" : '.*\([.,]\)' 2>/dev/null | tr -d '\n'`
nat='^[+-]?[0-9]+[.,]?$' \
dot="${1%[.,]*}${r}${1##*[.,]}" \
float='^[\+\-]?([.,0-9]+[Ee]?[-+]?|)[0-9]+$'
[[ "$1" == $dot ]] && [[ "$1" =~ $float ]] || [[ "$1" =~ $nat ]]
} # usage: parse_num -123.456
Ich benutze expr . Wenn Sie versuchen, einem nicht-numerischen Wert eine Null hinzuzufügen, wird eine Nicht-Null zurückgegeben:
if expr -- "$number" + 0 > /dev/null 2>&1
then
echo "$number is a number"
else
echo "$number isn't a number"
fi
Es kann möglich sein, bc zu verwenden, wenn Sie nicht ganze Zahlen benötigen, aber ich glaube nicht, dass bc
das gleiche Verhalten hat. Wenn Sie einer Nicht-Zahl Null hinzufügen, erhalten Sie Null und es wird auch ein Wert von Null zurückgegeben. Vielleicht können Sie bc
und expr
kombinieren. Verwenden Sie bc
, um Null zu $number
hinzuzufügen. Wenn die Antwort 0
lautet, überprüfen Sie mit expr
, ob $number
nicht Null ist.
Da musste ich mich in letzter Zeit etwas ändern und wie karttu's / Appoach mit dem Unit-Test am meisten. Ich habe den Code überarbeitet und einige andere Lösungen hinzugefügt. Probieren Sie es selbst aus, um die Ergebnisse zu sehen:
#!/bin/bash
# N={0,1,2,3,...} by syntaxerror
function isNaturalNumber()
{
[[ ${1} =~ ^[0-9]+$ ]]
}
# Z={...,-2,-1,0,1,2,...} by karttu
function isInteger()
{
[[ ${1} == ?(-)+([0-9]) ]]
}
# Q={...,-½,-¼,0.0,¼,½,...} by karttu
function isFloat()
{
[[ ${1} == ?(-)@(+([0-9]).*([0-9])|*([0-9]).+([0-9]))?(E?(-|+)+([0-9])) ]]
}
# R={...,-1,-½,-¼,0.E+n,¼,½,1,...}
function isNumber()
{
isNaturalNumber $1 || isInteger $1 || isFloat $1
}
bools=("TRUE" "FALSE")
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"
false_values="blah meh mooh blah5 67mooh a123bc"
for value in ${int_values} ${float_values} ${false_values}
do
printf " %5s=%-30s" $(isNaturalNumber $value) ${bools[$?]} $(printf "isNaturalNumber(%s)" $value)
printf "%5s=%-24s" $(isInteger $value) ${bools[$?]} $(printf "isInteger(%s)" $value)
printf "%5s=%-24s" $(isFloat $value) ${bools[$?]} $(printf "isFloat(%s)" $value)
printf "%5s=%-24s\n" $(isNumber $value) ${bools[$?]} $(printf "isNumber(%s)" $value)
done
So enthält isNumber () Bindestriche, Kommas und Exponentialschreibweise und gibt daher TRUE für ganze Zahlen und Floats zurück, wohingegen isFloat () für Integer-Werte FALSE und isInteger () zurückgibt FALSCH auf Schwimmern. Für Ihre Bequemlichkeit alle als ein Liner:
isNaturalNumber() { [[ ${1} =~ ^[0-9]+$ ]]; }
isInteger() { [[ ${1} == ?(-)+([0-9]) ]]; }
isFloat() { [[ ${1} == ?(-)@(+([0-9]).*([0-9])|*([0-9]).+([0-9]))?(E?(-|+)+([0-9])) ]]; }
isNumber() { isNaturalNumber $1 || isInteger $1 || isFloat $1; }
Dies kann erreicht werden, indem Sie mit grep
prüfen, ob die betreffende Variable mit einem erweiterten regulären Ausdruck übereinstimmt.
1120
:yournumber=1120
if [ $(echo "$yournumber" | grep -qE '^[0-9]+$'; echo $?) -ne "0" ]; then
echo "Error: not a number."
else
echo "Valid number."
fi
Ausgabe: Valid number.
1120a
:yournumber=1120a
if [ $(echo "$yournumber" | grep -qE '^[0-9]+$'; echo $?) -ne "0" ]; then
echo "Error: not a number."
else
echo "Valid number."
fi
Ausgabe: Error: not a number.
grep
, der -E
-Schalter ermöglicht die Verwendung des erweiterten regulären Ausdrucks '^[0-9]+$'
. Dieser reguläre Ausdruck bedeutet, dass die Variable nur []
die Zahlen 0-9
von null bis neun vom ^
bis zum $
-Ende der Variablen enthalten sollte und mindestens +
ein Zeichen enthalten sollte.grep
, der -q
quiet-Schalter schaltet jeden Ausgang aus, unabhängig davon, ob er etwas findet oder nicht.$?
ist der Beendigungsstatus des zuvor ausgeführten Befehls. Exit-Status 0
bedeutet Erfolg und alles Größere bedeutet Fehler. Der Befehl grep
hat den Exit-Status 0
, wenn er eine Übereinstimmung findet, und 1
, wenn dies nicht der Fall ist.$()
ist eine Subshell, mit der wir einen anderen Befehl ausführen und dann die Ausgabe verwenden können.Zusammengefasst, in einer $()
-Subshell, echo
die Variable $yournumber
und |
leiten es an grep
, die mit dem -q
-Schalter still den -E
-erweiterten regulären Ausdruck '^[0-9]+$'
passt. Wir echo
den $?
-Exit-Status. Dies wäre 0
, wenn grep
erfolgreich eine Übereinstimmung gefunden hat, und 1
, falls dies nicht der Fall ist.
Jetzt außerhalb der $()
-Subshell und zurück in der if
-Bedingung, nehmen wir die Ausgabe entweder 0
oder 1
aus der $()
-Subshell und prüfen, ob -ne
ungleich "0"
ist. Wenn dies nicht der Fall ist, lautet der Beendigungsstatus 1
, der nicht mit "0"
übereinstimmt. Dann werden wir echo "Error: not a number."
. Wenn die Übereinstimmung erfolgreich war, würde die Ausgabe des Exit-Status 0
lauten, was gleich "0"
ist, und andernfalls wir echo "Valid number."
.
Wir können den regulären Ausdruck für Floats oder Doubles einfach von '^[0-9]+$'
in '^[0-9]*+\.?[0-8]+$'
ändern.
1120.01
:yournumber=1120.01
if [ $(echo "$yournumber" | grep -qE '^[0-9]*+\.?[0-8]+$'; echo $?) -ne "0" ]; then
echo "Error: not a number."
else
echo "Valid number."
fi
Ausgabe: Valid number.
11.20.01
:yournumber=11.20.01
if [ $(echo "$yournumber" | grep -qE '^[0-9]*+\.?[0-8]+$'; echo $?) -ne "0" ]; then
echo "Error: not a number."
else
echo "Valid number."
fi
Ausgabe: Error: not a number.
Um negative Ganzzahlen zuzulassen, ändern Sie einfach den regulären Ausdruck von '^[0-9]+$'
in '^\-?[0-9]+$'
.
Um negative Fließ- oder Doppelpunkte zuzulassen, ändern Sie einfach den regulären Ausdruck von '^[0-9]*+\.?[0-8]+$'
in '^\-?[0-9]*+\.?[0-8]+$'
.
Das gleiche hier mit einem regulären Ausdruck, der den gesamten Teil und den Dezimalteil testet, getrennt durch einen Punkt.
re="^[0-9]*[.]{0,1}[0-9]*$"
if [[ $1 =~ $re ]]
then
echo "is numeric"
else
echo "Naahh, not numeric"
fi
Ich habe das Rezept von Ultrasawblade ausprobiert, da es mir am praktischsten erschien und es nicht funktionieren konnte. Am Ende habe ich jedoch einen anderen Weg gefunden, basierend auf anderen Parametern, diesmal mit Regex-Ersetzung:
[[ "${var//*([[:digit:]])}" ]]; && echo "$var is not numeric" || echo "$var is numeric"
Es entfernt alle: digit: class-Zeichen in $ var und prüft, ob noch eine leere Zeichenfolge vorhanden ist. Dies bedeutet, dass das Original nur Zahlen war.
Was mir an diesem Gerät gefällt, ist seine geringe Stellfläche und Flexibilität. In dieser Form funktioniert es nur für nicht begrenzte 10-Ganzzahlen, obwohl Sie Pattern Matching verwenden können, um es an andere Bedürfnisse anzupassen.
Sie könnten "let" auch so 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
[ ~]$
Ich bevorzuge jedoch den "= ~" Bash 3+ -Operator, wie einige Antworten in diesem Thread.
zu überprüfende Variable
number=12345
oder number=-23234
oder number=23.167
oder number=-345.234
Überprüfen Sie numerisch oder nicht numerisch
echo $number | grep -E '^-?[0-9]*\.?[0-9]*$' > /dev/null
entscheiden Sie sich für weitere Aktionen auf der Grundlage des Beendigungsstatus der oben genannten
if [ $? -eq 0 ]; then echo "Numeric"; else echo "Non-Numeric"; fi
Wenn Sie David Ws Antwort aus dem Oktober '13 verfolgen, könnte dies bei Verwendung von expr
besser sein
test_var=`expr $am_i_numeric \* 0` >/dev/null 2>&1
if [ "$test_var" = "" ]
then
......
Bei Zahlen, multipliziert mit 1, erhalten Sie denselben Wert (einschließlich negativer Zahlen). Ansonsten erhalten Sie null
, die Sie testen können
Ich benutze printf als andere Antwort, wenn Sie die Formatzeichenfolge "% f" oder "% i" angeben, wird printf die Überprüfung für Sie durchführen. Die Syntax ist einfacher als die Neuerfindung der Prüfungen, sie ist einfach und kurz und printf ist allgegenwärtig. Daher ist es meiner Meinung nach eine gute Wahl - Sie können auch die folgende Idee verwenden, um nach einer Reihe von Dingen zu suchen. Sie ist nicht nur nützlich, um Zahlen zu überprüfen.
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; }
Um negative Zahlen zu fangen:
if [[ $1 == ?(-)+([0-9.]) ]]
then
echo number
else
echo not a number
fi
Ich habe eine recht kurze Version gefunden:
function isnum()
{
return `echo "$1" | awk -F"\n" '{print ($0 != $0+0)}'`
}
printf '%b' "-123\nABC" | tr '[:space:]' '_' | grep -q '^-\?[[:digit:]]\+$' && echo "Integer." || echo "NOT integer."
Entfernen Sie den -\?
im grep-Abgleichmuster, wenn Sie keine negative Ganzzahl akzeptieren.
Für mein Problem musste ich nur sicherstellen, dass ein Benutzer nicht versehentlich Text eingibt, und ich habe versucht, ihn einfach und lesbar zu halten
isNumber() {
(( $1 )) 2>/dev/null
}
Laut Manpage macht das so ziemlich das, was ich will
Wenn der Wert des Ausdrucks nicht Null ist, ist der Rückgabestatus 0
Um unangenehme Fehlermeldungen für Zeichenfolgen zu vermeiden, bei denen es sich möglicherweise um Zahlen handelt, ignoriere ich die Fehlerausgabe
$ (( 2s ))
bash: ((: 2s: value too great for base (error token is "2s")
Ich mag die Antwort von Alberto Zaccagni.
if [ "$var" -eq "$var" ] 2>/dev/null; then
Wichtige Voraussetzungen: - Es wurden keine Subshells erstellt - Keine RE-Parser wurden aufgerufen - Die meisten Shell-Anwendungen verwenden keine reellen Zahlen
Wenn $var
jedoch komplex ist (z. B. ein assoziativer Array-Zugriff) und die Zahl eine nicht negative ganze Zahl ist (die meisten Anwendungsfälle), ist dies möglicherweise effizienter.
if [ "$var" -ge 0 ] 2> /dev/null; then ..
Quick & Dirty: Ich weiß, dass dies nicht der eleganteste Weg ist, aber ich habe normalerweise nur eine Null hinzugefügt und das Ergebnis getestet. wie so:
function isInteger {
[ $(($1+0)) != 0 ] && echo "$1 is a number" || echo "$1 is not a number"
}
x=1; isInteger $x
x="1"; isInteger $x
x="joe"; isInteger $x
x=0x16 ; isInteger $x
x=-32674; isInteger $x
$ (($ 1 + 0)) gibt 0 oder Bombe zurück, wenn $ 1 KEINE Ganzzahl ist. zum Beispiel:
function zipIt { # quick Zip - unless the 1st parameter is a number
ERROR="not a valid number. "
if [ $(($1+0)) != 0 ] ; then # isInteger($1)
echo " backing up files changed in the last $1 days."
OUT="zipIt-$1-day.tgz"
find . -mtime -$1 -type f -print0 | xargs -0 tar cvzf $OUT
return 1
fi
showError $ERROR
}
HINWEIS: Ich denke, ich hätte nie daran gedacht, nach Floats oder gemischten Typen zu suchen, mit denen die gesamte Skriptbombe bombiert wird. Ich werde mit mruccis Lösung und Duffys Regex herumspielen - sie scheinen die robustesten im Bash-Rahmen zu sein ...
Ich verwende Folgendes (für ganze Zahlen):
## ##### constants
##
## __TRUE - true (0)
## __FALSE - false (1)
##
typeset -r __TRUE=0
typeset -r __FALSE=1
## --------------------------------------
## isNumber
## check if a value is an integer
## usage: isNumber testValue
## returns: ${__TRUE} - testValue is a number else not
##
function isNumber {
typeset TESTVAR="$(echo "$1" | sed 's/[0-9]*//g' )"
[ "${TESTVAR}"x = ""x ] && return ${__TRUE} || return ${__FALSE}
}
isNumber $1
if [ $? -eq ${__TRUE} ] ; then
print "is a number"
fi
Wenn Sie Perl installiert haben, ist dieser eine Liner einfach, lesbar und erweiterbar
Perl -se 'exit($n !~ /\d+/)' -- -n=a
Hier sind einige Tests
Perl -se 'exit($n !~ /\d+/)' -- -n=a; echo $?
1
Perl -se 'exit($n !~ /\d+/)' -- -n=2; echo $?
0
Es ist ziemlich selbst erklärt, aber hier sind mehr Informationen
-e
ermöglicht die Auswertung-s
ermöglicht das Übergeben von Argumenten nach - in diesem Fall -n
!~
ist der Negationsregexp-Übereinstimmungsoperator. Da 0 in bash Erfolg ist, möchten wir, dass er erfolgreich beendet wird, wenn das Argument -n
eine Zahl istSie möchten dies in eine Funktion einschließen, hier eine bessere Version, die auch Floats lesen kann
is_number() { Perl -se 'exit($n !~ /^\d+(\.\d+)?$/)' -- -n="$1"; }