I'm trying to do something common enough: Parse user input in a shell script. If the user provided a valid integer, the script does one thing, and if not valid, it does something else. Trouble is, I haven't found an easy (and reasonably elegant) way of doing this - I don't want to have to pick it apart char by char.
I know this must be easy but I don't know how. I could do it in a dozen languages, but not BASH!
In my research I found this:
Regular expression to test whether a string consists of a valid real number in base 10
And there's an answer therein that talks about regex, but so far as I know, that's a function available in C (among others). Still, it had what looked like a great answer so I tried it with grep, but grep didn't know what to do with it. I tried -P which on my box means to treat it as a PERL regexp - nada. Dash E (-E) didn't work either. And neither did -F.
Just to be clear, I'm trying something like this, looking for any output - from there, I'll hack up the script to take advantage of whatever I get. (IOW, I was expecting that a non-conforming input returns nothing while a valid line gets repeated.)
snafu=$(echo "$2" | grep -E "/^[-+]?(?:\.[0-9]+|(?:0|[1-9][0-9]*)(?:\.[0-9]*)?)$/")
if [ -z "$snafu" ] ;
then
echo "Not an integer - nothing back from the grep"
else
echo "Integer."
fi
Would someone please illustrate how this is most easily done?
Frankly, this is a short-coming of TEST, in my opinion. It should have a flag like this
if [ -I "string" ] ;
then
echo "String is a valid integer."
else
echo "String is not a valid integer."
fi
Here's yet another take on it (only using the test builtin command and its return code):
Wow... there are so many good solutions here!! Of all the solutions above, I agree with @nortally that using the
-eq
one liner is the coolest.I am running GNU bash, version
4.1.5
(Debian). I have also checked this on ksh (SunSO 5.10).Here is my version of checking if
$1
is an integer or not:This approach also accounts for negative numbers, which some of the other solutions will have a faulty negative result, and it will allow a prefix of "+" (e.g. +30) which obviously is an integer.
Results:
The solution provided by Ignacio Vazquez-Abrams was also very neat (if you like regex) after it was explained. However, it does not handle positive numbers with the
+
prefix, but it can easily be fixed as below:^
indicates the beginning of the input pattern-
is a literal "-"?
means "0 or 1 of the preceding (-
)"+
means "1 or more of the preceding ([0-9]
)"$
indicates the end of the input patternSo the regex matches an optional
-
(for the case of negative numbers), followed by one or more decimal digits.References:
I like the solution using the
-eq
test, because it's basically a one-liner.My own solution was to use parameter expansion to throw away all the numerals and see if there was anything left. (I'm still using 3.0, haven't used
[[
orexpr
before, but glad to meet them.)Latecomer to the party here. I'm extremely surprised none of the answers mention the simplest, fastest, most portable solution; the
case
statement.The trimming of any sign before the comparison feels like a bit of a hack, but that makes the expression for the case statement so much simpler.
You can strip non-digits and do a comparison. Here's a demo script:
This is what the test output looks like: