Reputation: 1235
I have one problem in unix shell scripting. Let me ask you with very simple example.
suppose, I am getting user input and comparing two numbers.
echo "Enter the first number"
read a
echo "Enter the second number"
read b
if [ a -gt b ]---------------------->I have not used $ before variable name.
then
echo "a is greater"
else
echo "b is greater"
fi
In this example, i should have used $ to get the value of variable. By mistake, I forgot. Still, it gives me right result, how and why?
I tried to debug by using sh -x filename. but, it doesn't show any value while comparing(because i havn't used $ sign).
How the shell decide which is greater and vice versa? How it works internally?
Thanks.
Upvotes: 2
Views: 256
Reputation: 155196
There is a simple explanation why your test appears to work: it blindly executes the else
clause.
The [ ... ]
built-in has no way to report the error to the caller except by exiting with a non-zero exit status. Incidentally, a non-zero exit status is also used to indicate "false". This means that if
cannot distinguish between a false and an erroneous evaluation of its condition, which is why your comparison always prefers the else
branch and thus appears to work. You can easily test it by reverting the arguments:
$ if [ b -gt a ]
then
echo "b is greater"
else
echo "a is greater"
fi
dash: 11: [: Illegal number: b
a is greater
Note that the error message printed to standard error is, as far as the if
statement is concerned, a mere side effect of the test command, and is entirely ignored.
Upvotes: 2
Reputation: 295619
Notably, you could use this without a $
if you did the comparison in a numeric context.
In bash:
if (( a > b )); then
echo "a is greater"
else
echo "b is greater"
fi
...would be correct, as (( ))
(double parens) enters a numeric context within which all textual strings are treated as variables and automatically dereferenced (and within which operators such as >
and <
have their typical arithmetic meanings, rather than performing redirections).
What you're doing now is heavily implementation-dependent. [ a '>' b ]
would be a lexographic comparison between the letters a
and b
. [ a -gt b ]
is an arithmetic test.
Many shells will not allow this at all. For instance:
$ a=2; b=3; [ a -gt b ]; echo $?
-bash: [: a: integer expression expected
2
Notably, this is different inside of bash's [[ ]]
test context (which doesn't carry the POSIX semantics of [ ]
). There, what you're doing actually does work, though it's harder to read than the (( ))
form:
$ a=2; b=3; [[ a -gt b ]]; echo $?
1
$ a=3; b=2; [[ a -gt b ]]; echo $?
0
If you're limited to POSIX sh, you don't have (( ))
, but you do have $(( ))
, which you can use almost the same way:
$ a=2; b=3; result=$(( a > b ? 1 : 0 )); echo "$result"
0
$ a=3; b=2; result=$(( a > b ? 1 : 0 )); echo "$result"
1
Upvotes: 6