2
\$\begingroup\$

I have a script used for installing few rpms depending on operating system type. Here in this example, the script will install packages on two system "centos" and "suse". The system names are listed in nodes.txt and read as an input while executing the script.

For example:

~]# cat systems.txt

centos
suse


~]# ./myscript.sh systems.txt

There are two scripts written which does the same purpose. One is written using "if-else" and other using "case".

When I use "if-else" condition script, the execution (i.e installation of rpms) completes much faster than using the "case" condition script. Both scripts does the same job, except that the control structure is different. I will have many hundreds of installation criteria listed in the script, and will add/remove new system types within systems.txt file.

Hence I am not sure which condition is better to choose, and considering my use case. Can someone help me know why does case script taking more time to execute when compared if-else? Any help/recommendations?

Below the case script which took 10 secs to complete.

#! /bin/bash

while read -d $'\n' -r node
do

# Each node has a unique id assigned and used along with install script
id=$(./name.sh -getid)

case $node in
   centos)
echo $(./install.sh --resourceId=$id --name=httpd)
echo $(./install.sh --resourceId=$id --name=gcc)
      ;;

    suse)
echo $(./install.sh --resourceId=$id --name=compact)
echo $(./install.sh --resourceId=$id --name=glib)
      ;;

   *)
        echo "#No resources found for the node"
    ;;
esac
done < "$1"

Below the if-else script which took 5 secs to complete:

#!/bin/bash
while read -d $'\n' -r node
do

# Each node has a unique id assigned and used along with install script
id=$(./name.sh -getid)

if [ $node == centos ]
then

echo $(./install.sh --resourceId=$id --name=httpd)
echo $(./install.sh --resourceId=$id --name=gcc)

elif [ $node == suse ]
then

echo $(./install.sh --resourceId=$id --name=compact)
echo $(./install.sh --resourceId=$id --name=glib)

else

echo "#No resources found for the node"

fi
done < "$1"
\$\endgroup\$
  • \$\begingroup\$ one factor that will make a difference is that case will be doing pattern matching, and [ x == y ] is checking for string equality. With no wildcards, case may well be optimized. You'd have to check the bash source. \$\endgroup\$ – glenn jackman Jul 15 '14 at 1:18
3
\$\begingroup\$

This problem has me perplexed. Frankly, I don't believe you ;-) !!!

There is no logical reason for this code to be so different from each other. There must be something else going on.... For a start, the bash process itself is probably taking almost no time at all, and all the time will be spent running the 'install' sub-processes. I imagine that you are running the install processes twice as many times for some reason.... or that, subsequent installs are faster because you don't need to access the disk/net, or something.

Regardless, I don't believe the difference in performance is because of the case vs. if

As a side note, do you need to execute the installs in a sub-shell and capture the results like you do and then echo them? The install lines should all look similar to:

# Relace this: echo $(./install.sh --resourceId=$id --name=httpd)
# with:
./install.sh --resourceId=$id --name=httpd
\$\endgroup\$
1
\$\begingroup\$

I tried to slim your question down to see if it had any thing to do with only the case statement, and if condition. Here was my script

$ cat y.sh
#!/bin/bash
a=a
for i in `seq 1 1000000`
do
if [ $a == a ]
then 
  :;
elif [ $a == b ]
then 
  :;
fi
done

And here is the other script

$ cat x.sh
#!/bin/bash
a=a
for i in `seq 1 1000000`
do
case $a in
  a) :;;
  b) :;;
  *) :;;
esac
done

Rather interestingly, here is the rough output, which remains within a small margin over many runs

$ time ./x.sh
./x.sh  2.54s user 0.06s system 95% cpu 2.723 total
$ time ./y.sh
./y.sh  4.28s user 0.07s system 96% cpu 4.508 total

As you suggested, there is a difference, however, it seems that the difference is actually in favour of case statement rather than if. I am not sure what to make of it, especially since you seem to have a different result. However, the time difference does remain if I increase the number of loops.

10000000
$ time ./x.sh
./x.sh  26.61s user 1.55s system 90% cpu 31.140 total
$ time ./y.sh
./y.sh  43.04s user 0.66s system 97% cpu 45.001 total
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.