A question about bash ....
I wrote a little code to check whether a year is a leapyear. The relevant part looks like:
if [ $testnum4 -eq 0 -a $testnum100 -ne 0 ] || [ $testnum400 -eq 0 ]
then
echo 0
fi
Well, this code actually works. My problem is that I'm still not quite sure what I was doing. Just to see what would happen, I have tried several variations on this: enclosing the entire test expression in square backets, using &&
where I have -a
and -o
where I have ||
, etc. Nothing works except for the one expression that I wrote above. I stumbled on it, and I'm glad I did, but the next time I have to do something like this, I would like to know what I am doing.
So: Anyone have a quick explanation of how compound tests work in bash? or a pointer to a good resource on this topic?
Thanks.
Here's a code that failed:
let testnum4=$1%4
let testnum100=$1%100
let testnum400=$1%400
if [ $testnum4 -eq 0 && $testnum100 -ne 0 ] -o [ $testnum400 -eq 0 ]
then
echo 0
fi
Little note of interest: The square braces are actually a Unix command. See if there's a file called /bin/[
or /usr/bin/[
on your system. In fact, try this:
$ ls i-il /bin[ /bin/test
571541 -r-xr-xr-x 2 root wheel 43120 Aug 17 2011 /bin/[
571541 -r-xr-xr-x 2 root wheel 43120 Aug 17 2011 /bin/test
That first number is the i-node number. You see that /bin/[
and /bin/test
are hard linked to each other. They're the same program.
I'll get back to the significance of this a bit later...
In BASH and other Bourne type shells, the if
command merely runs the command, and if the command returns an exit code of 0
, it executes the commands in the if
clause. If the command does not return an exit code of 0
, it skips the commands in the if
clause and executes the commands in the else
clause if it exists.
Thus, this is also valid:
if sleep 2
then
echo "That was a good nap!"
fi
Your computer executes the sleep 2
command which (if the sleep command exists) will return a zero exit code and continue to echo That was a good nap!.
That's all the if
command really does. It runs the given command and examines the exit code.
Now, back to the [
...
You might want to look at the manpage for the test command. You can see that the test
command seems to have many of the same type of tests as the [...]
in the if statement. In fact, in the original Bourne shell (which BASH is derived from) these are the same command structure:
if test -f $my_file
then
echo "File $my_file exists"
else
echo "There is no file $my_file"
fi
if [ -f $my_file ]
then
echo "File $my_file exists"
else
echo "There is no file $my_file"
fi
In fact, in the original Bourne shell, you had to use the test
command and not the square brackets.
So, back to your original question. The -a
and -o
are parameters for the test command (see the test
manpage. For example, your if
statement could have been written as this:
if test $testnum4 -eq 0 -a $testnum100 -ne 0 || test $testnum400 -eq 0
then
echo 0
fi
However, the &&
and ||
are not test command parameters, so they can't be used inside the test command.
Note that [
is a built in command in BASH, so BASH does not execute /bin/[
as the original Bourne shell would have. However, it is still a command much like echo
is a built in command in BASH although /bin/echo
also still exists.
The correct way to do integer comparisons in Bash is to use double parentheses:
if (( (testnum4 == 0 && testnum100 != 0) || testnum400 == 0 ))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With