Discussion:
process result code in if
A.P. Horst
2013-06-06 09:00:51 UTC
Permalink
Hi,

I am trying to do a simple check to validate a value is a positive
integer. There are many variations to do this but in general this should
do the trick:
var=100
if echo "$var" | grep -Eq '^[0-9]+$' > /dev/null 2>&1; then
echo "positive integer"
else
echo "something else"
fi

if I put this in a file and execute it, it works as expected. But if I
put it in my configure.ac, it doesn't work!
Also when I just have:
echo "$var" | grep -Eq '^[0-9]+$'
echo "$?"

the 'normal' script prints "0" if var is set to an integer and "1" when
set to something else. But the configure script prints "1" no matter
what I set var to.

I must be missing out on something because I took this construct from
another configure.ac which worked just fine.

I am on a win7 x64 machine with MinGW 3.20 and W32API 3.17
sh --version
GNU bash, version 3.1.17(1)-release (i686-pc-msys)

Arie
Earnie Boyd
2013-06-06 11:12:50 UTC
Permalink
Post by A.P. Horst
echo "$var" | grep -Eq '^[0-9]+$'
echo "$?"
-->8--
Post by A.P. Horst
I am on a win7 x64 machine with MinGW 3.20 and W32API 3.17
sh --version
GNU bash, version 3.1.17(1)-release (i686-pc-msys)
How is the var variable set? If you're using the output of a compiled
program, I'm guessing the issue is CRLF versus just LF. MSYS will not
remove the CR from the variable. Add the /mingw/lib/binmode.o to the
compiled program or use _setmode on stdout to make it _O_BINARY.
http://msdn.microsoft.com/en-us/library/tw4k6df8(v=vs.110).aspx
--
Earnie
-- https://sites.google.com/site/earnieboyd
Keith Marshall
2013-06-06 11:54:18 UTC
Permalink
Post by Earnie Boyd
Post by A.P. Horst
echo "$var" | grep -Eq '^[0-9]+$'
echo "$?"
-->8--
Post by A.P. Horst
I am on a win7 x64 machine with MinGW 3.20 and W32API 3.17
sh --version
GNU bash, version 3.1.17(1)-release (i686-pc-msys)
How is the var variable set? If you're using the output of a compiled
program, I'm guessing the issue is CRLF versus just LF. MSYS will not
remove the CR from the variable. Add the /mingw/lib/binmode.o to the
compiled program or use _setmode on stdout to make it _O_BINARY.
http://msdn.microsoft.com/en-us/library/tw4k6df8(v=vs.110).aspx
Another (more likely) possibility is that the shell fragment is under
quoted, where it appears in configure.ac. Look for that fragment in
the generated configure script: I suspect you may find that the []
surrounding the [0-9] expression have been swallowed by autoconf; (they
are the autoconf quoting characters.
--
Regards,
Keith.
Keith Marshall
2013-06-06 12:21:28 UTC
Permalink
Post by Keith Marshall
Post by Earnie Boyd
Post by A.P. Horst
echo "$var" | grep -Eq '^[0-9]+$'
...
How is the var variable set? If you're using the output of a compiled
program, I'm guessing the issue is CRLF versus just LF. ...
Another (more likely) possibility is that the shell fragment is under
quoted, where it appears in configure.ac. ...
BTW, even when you've corrected the under quoting issue, this

echo $var | grep -Eq '^[0-9]+$'

test that $var represents a positive integer doesn't really "cut the
mustard"; there are two reasons:

1) It completely neglects to consider any initial unary + sign, so
would reject any representation such as var=+50

2) grep -Eq ... is not portable; not all implementations of grep support
GNU grep's -E and -q options.

A more robust, (and more portable), formulation may be:

echo $var | grep '^+\{0,1\}[0-9]\{1,\}$' > /dev/null 2>&1
--
Regards,
Keith.
Eric Blake
2013-06-06 12:41:23 UTC
Permalink
----- Original Message -----
Post by Keith Marshall
echo $var | grep '^+\{0,1\}[0-9]\{1,\}$' > /dev/null 2>&1
Why fork, when straight shell will do?

case $var in
+*) tmp=$var ;;
*) tmp=+$var ;;
esac
case $tmp in
+*[!0-9]* | +) echo "not numeric" ;;
*) echo integer ;;
esac

Again, when placing this in autoconf.ac, you need to quote the
[0-9] since m4 eats one level of [], either by writing [[0-9]]
in place, or by using [] around the entire case snippet.
--
Eric Blake ***@redhat.com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
Keith Marshall
2013-06-06 13:25:44 UTC
Permalink
Post by Eric Blake
Post by Keith Marshall
echo $var | grep '^+\{0,1\}[0-9]\{1,\}$' > /dev/null 2>&1
Why fork, when straight shell will do?
case $var in
...
Agreed, avoiding the fork is a good idea, and I do often use case
statements myself, much as you suggest, (although it may be considered
a less obvious solution).

My point was more that the OP's use of grep didn't use a particularly
effective expression for his (perceived) task, and that his use of
grep options wasn't portable.
--
Regards,
Keith.
Andres Perera
2013-06-06 22:56:55 UTC
Permalink
Post by Eric Blake
----- Original Message -----
Post by Keith Marshall
echo $var | grep '^+\{0,1\}[0-9]\{1,\}$' > /dev/null 2>&1
Why fork, when straight shell will do?
yea, forking for grep is probably going to make your script significantly slower
Post by Eric Blake
case $var in
+*) tmp=$var ;;
*) tmp=+$var ;;
esac
case $tmp in
+*[!0-9]* | +) echo "not numeric" ;;
*) echo integer ;;
esac
i've found through benchmarks that certain shells (dash and bash and
ksh) are optimized towards if statements over case ones

i would parse the number like this for best performance, but make a
copy for $var because it's destructive:

trim()
{
n=$1 v=$2
while [ ${#v} -ne $n ]
do
v=${v%?}
done
echo $v
}

if [ -z "$var" ]; then
echo "ENOTNUM $var" >&2
exit 2
fi

if [ $(trim 1 $var) = '+' ]; then
echo "we got a signed number; begin normalizing procedure"
var=${var#?}
fi

while [ ${#var} -ne 0 ]
do
if [ ${var%${var#?}} = '0' ] || [ ${var%${var#?}} = '1' ] || [
${var%${var#?}} = '2' ] || [ ${var%${var#?}} = '3' ]; then
echo "digit is base 4"
else
echo "ENOTNUM $var" >&2
exit 2
fi
var=${var#?}
done
Post by Eric Blake
Again, when placing this in autoconf.ac, you need to quote the
[0-9] since m4 eats one level of [], either by writing [[0-9]]
in place, or by using [] around the entire case snippet.
--
Libvirt virtualization library http://libvirt.org
_______________________________________________
Autoconf mailing list
https://lists.gnu.org/mailman/listinfo/autoconf
Miles Bader
2013-06-07 01:41:26 UTC
Permalink
Wait, why can't you use "test $x -gt 0"...?

-miles
--
Logic, n. The art of thinking and reasoning in strict accordance with the
limitations and incapacities of the human misunderstanding.
Gary V. Vaughan
2013-06-07 02:25:09 UTC
Permalink
Post by Miles Bader
Wait, why can't you use "test $x -gt 0"...?
You mean "test 0 -lt $x", otherwise if x starts with a hyphen (e.g -1) things will go awry!

Cheers,
--
Gary V. Vaughan (gary AT gnu DOT org)
Miles Bader
2013-06-07 03:13:24 UTC
Permalink
Post by Gary V. Vaughan
Post by Miles Bader
Wait, why can't you use "test $x -gt 0"...?
You mean "test 0 -lt $x", otherwise if x starts with a hyphen (e.g -1) things will go awry!
I dunno, test here (both coreutils test, and the bash builtin) seems
to handle negative numbers just fine using "test $x -gt 0" ...

[I suppose maybe there are broken versions of test out there, the
usual issue with just about anything in autoconf... typically Sun... >< ]

-miles
--
`The suburb is an obsolete and contradictory form of human settlement'
A.P. Horst
2013-06-07 06:08:09 UTC
Permalink
Post by Miles Bader
Post by Gary V. Vaughan
Post by Miles Bader
Wait, why can't you use "test $x -gt 0"...?
You mean "test 0 -lt $x", otherwise if x starts with a hyphen (e.g -1)
things will go awry!
I dunno, test here (both coreutils test, and the bash builtin) seems
to handle negative numbers just fine using "test $x -gt 0" ...
[I suppose maybe there are broken versions of test out there, the
usual issue with just about anything in autoconf... typically Sun... >< ]
-miles
Thanks for all the great input! Seems google isn't always your best
friend, at least not when it comes to autoconf. The solution with the
test command is very elegant and readable.
I ended up using this:
if ! test $var -gt 0 > /dev/null 2>&1; then
<not a positive integer>
fi

This works also when something else than a number or nothing at all is
given.

I will try to remember autoconf also eats brackets.

arie
Miles Bader
2013-06-07 06:46:44 UTC
Permalink
Post by A.P. Horst
if ! test $var -gt 0 > /dev/null 2>&1; then
Incidentally, test should never produce any output on stdout, so you
can just use "2>/dev/null" instead of "> /dev/null 2>&1"... :]

-miles
--
P.S. All information contained in the above letter is false,
for reasons of military security.
Tim Rice
2013-06-07 13:34:26 UTC
Permalink
Thanks for all the great input! Seems google isn't always your best friend, at
least not when it comes to autoconf. The solution with the test command is
very elegant and readable.
if ! test $var -gt 0 > /dev/null 2>&1; then
<not a positive integer>
fi
"if ! test ..." is definitely not portable.
This works also when something else than a number or nothing at all is given.
I will try to remember autoconf also eats brackets.
arie
--
Tim Rice Multitalents
***@multitalents.net
Miles Bader
2013-06-07 22:11:08 UTC
Permalink
Post by Tim Rice
Post by A.P. Horst
if ! test $var -gt 0 > /dev/null 2>&1; then
"if ! test ..." is definitely not portable.
Hmmm, I can never remember which is the portable one, but from the
autoconf docs, one should usually use "if test ! ..." instead :

It is safe to use `!' as a `test' operator. For example, `if
test ! -d foo; ...' is portable even though `if ! test -d foo;
...' is not.

However in this case, because he wants specific behavior for the case
where test gives a syntax error, I guess it's better to instead use
"if test ... then : ; else ..."
Post by Tim Rice
<
-miles
--
The secret to creativity is knowing how to hide your sources.
--Albert Einstein
Loading...