Dynamic case creation based on output list from a command

I am attempting to create a script that would allow me to list all the instances associated with a DB2 and then prompt the user to choose which one to issue the db2profile command against. I use the db2 command db2ilist to get a list of the instances for a particular server, but the number of instances could vary from server to server and I can't figure out how use the results from the db2ilist to create a case.

The output from db2ilist looks like this for example

[sslaton@Z11LD003 ~]$ db2ilist
dtrnd1
scgnd1
scgnd2
scgnd3
dtrnl1
scgnl1
scgnl2
scgnl3

I created a dumbed down version where I hard coded those instances to create a pick list to demonstrate what I'd like to do.

#!/bin/sh
echo "DB2 INSTANCE PROFILER UTILITY"
echo "1 = DTRND1"
echo "2 = SCGND1"
echo "3 = SCGND2"
echo "4 = SCGND3"
echo "5 = DTRNL1"
echo "6 = SCGNL1"
echo "7 = SCGNL2"
echo "8 = SCGNL3"
echo "Please enter the number of the instance you want to profile:\c"
read name

case $name in
 "1") . /dbhome/dtrnd1/sqllib/db2profile
      db2 get instance;;
 "2") . /dbhome/scgnd1/sqllib/db2profile
      db2 get instance;;
 "3") . /dbhome/scgnd2/sqllib/db2profile
      db2 get instance;;
 "4") . /dbhome/scgnd3/sqllib/db2profile
      db2 get instance;;
 "5") . /dbhome/dtrnl1/sqllib/db2profile
      db2 get instance;;
 "6") . /dbhome/scgnl1/sqllib/db2profile
      db2 get instance;;
 "7") . /dbhome/scgnl2/sqllib/db2profile
      db2 get instance;;
 "8") . /dbhome/scgnl3/sqllib/db2profile
      db2 get instance;;

     *) echo "Your did not pick a valid instance";;
esac

What I want to create is one script I can run on any server so I'm attempting to do something similar using the output of db2ilist. I can build the pick list, but I'm not sure how I can use that output to dynamically create a case.

#!/bin/sh
echo "DB2 INSTANCE PROFILER UTILITY"
ilist=$(db2ilist)
i='0'

for instance in $ilist
do
i=`expr $i + 1`
echo $i " = " $instance



done

Bumping up posts or double posting is not permitted in these forums.

Please read the rules, which you agreed to when you registered, if you have not already done so.

You may receive an infraction for this. If so, don't worry, just try to follow the rules more carefully. The infraction will expire in the near future

Thank You.

The UNIX and Linux Forums.

>>> On request of user, opening this thread and closing the other.

1 Like

Hi!

IMHO if you could use bash instead of sh, there would be a trivial solution using select instead of case:

#!/bin/bash
INSTANCE=""
while [[ $INSTANCE = "" ]]; do
    echo "DB2 INSTANCE PROFILER UTILITY"
    echo "Please enter the number of the instance you want to profile:"
    select INSTANCE in $(db2ilist); do
         if [[ $INSTANCE = "" ]]; then
              echo "Please enter a valid number. Retry."
         else {
              . /dbhome/${INSTANCE}/sqllib/db2profile
              db2 get instance; }
          fi
          break
          done
     done
exit 0

I don't think it's possible to do it dinamically with case.

1 Like

Of course it is. Bash isn't a shell well suited to scripting at all IMHO and should be avoided at all costs.

I suspect you are on an AIX system (btw. always say which system you work on - they all differ in some or other subtle regard and the answer you get might not work on your particular OS) and then "sh" is just a link to a ksh88. I am gonna use that as a basis for the script.

Your script will not work with "case"s like you did in the static version, but with a simple consistency check:

First, we read the output of "db2ilist" into an array:

#!/bin/ksh

typeset -i iCnt=0
typeset    chInstance=""
typeset -u chUInst=""
typeset -i iSelect=0
typeset    chSelect=""

(( iCnt = 1 ))
db2ilist | while read chInstance ; do
     achInstName[$iCnt]="$chInstance"
     (( iCnt += 1 ))
done

We now have an array with all the instance names. No we will use this to display a list of them along with a choice:

tput clear
print - "Enter the corresponding number to start the instance:\n"
(( iCnt = 1 ))
while [ $iCnt -le ${#achInstName[*]} ] ; do
     chUInst="${achInstName[$iCnt]}"
     printf "%2d)  %15s\n" "$iCnt" "$chUInst"
     (( iCnt += 1 ))
done
print - "\n\n      Enter your pick (0 to abort) ==>"
read chSelect

Now that we have displayed the menu and gotten some user response in "$chSelect", we have to make sure the pick is valid - an integer and within the range of our array.

the first test is if the text entered is an integer number at all - only digits 0-9, nothing else. We throw these digits out and if anything remains the users pick was invalid. Otherwise we copy this to a predefined integer variable.

The next test is if it is a "0", which means "Abort" - we exit.

Then a test, if it is between 1 and the maximum index of our array - if no, we complain and exit (start over?) if yes, we have a valid answer and continue.

if [ "$(print - $chSelect | tr -d '0-9')" != "" ] ; then
     print -u2 "Error: only the given numbers or 0 as input allowed." 
     exit 1
else
     iSelect=$chSelect
fi

if [ $iSelect -eq 0 ] ; then
     print -u2 "User selected abort, exiting..."
     exit 0
fi

if [ $iSelect -le ${#achInstName[*]} ] ; then
     . /dbhome/${achInstName[$iSelect]}/sqllib/db2profile
     db2 get instance
else
     print -u2 "Error: User entered an invalid pick number. Exiting."
     exit 1
fi

exit 0

I hope everything is well understandable from my comments. some of the not-so-obvious devices explained:

"${#arrayname[*]}" expands to the number of elements in the array.

"typeset -u" declares a variable which content is automatically converted to upper case upon load. Sort-of a built-in "toupper()" function.

I hope this helps.

bakunin

2 Likes

Of course it is possible to solve the problem in many ways, but I still don't see a way to dinamically create the entries of a case command.
In bash there's select command for this kind of things.
If I'm wrong, which is always extremely possible when the matter is shell scripting, I'd really appreciate a hint from you about the solution.

My shells knowledge is so little that I can't discuss this topic.
But I'm a bit.. confused.

What was so wrong with my script?
And, of course, also in bash you can use an array as you've done in ksh (moreover, it had been my first think: but then select came to my mind, and it does the work, and it's much quicker. So why not use it, if bash is available?).

LOL! :slight_smile:
Of course you're speaking to the OP.
AIX... I'm not a sysadmin, nor my job is heavily computer related. So, AIX... (AKA "blood and tears", as someone says): I - personally - have never seen an AIX system. :slight_smile:

This is correct, i'll give you that. Sorry for misreading your post before, but i was under the impression that you mean it is not possible to solve the problem while you obviously meant it is not possible to create case-statements dynamically.

Regarding bash not being well suited for scripting.

Sorry again, what i said was just an off-topic remark. The reasons for this personal opinion of mine are many but it is quite off-topic here to discuss it. If you are interested I'll send you some pointers per PM, we even have some threads here aobut the shortcomings of bash compared to ksh.

Nothing at all. If you compare my script and yours closely the logic is similar. The difference is i commented it heavily (the threads O/P comes across as not so experienced in shell scripting and probably will need that to understand the flow of the program), i explained how he could implement the input checks, which come with the "case..esac" and which are missing in your script and i used the shell i suppose he already uses (ksh) because of - as stated - i suppose he works on an AIX system. The reason for this is he uses DB/2 as a database, which is from IBM. AIX is IBMs Unix derivate and it is conceivable that a company buying the database from one vendor will buy the hardware and the OS from the same vendor.

"select" as well as arrays are available in ksh and bash alike - even with an identical syntax. I decided against it in my solution because i wanted better control over the output ("select" always goes to <stderr> for instance) and the program flow. It is just usually better to stick to the default shell on any system. For the same reasons i advocate the ksh here on a - probable- AIX system i would advocate using the bash on, say, a GNU/Linux system, even if i still think ksh is the better shell, but that is just personal conviction. ksh is the default shell here, bash is the one there and hence they should be used accordingly if at all possible.

Yes, that was addressing the OP. AIX evolved from being "the best MVS IBM ever created" (this was the saying back in the days of AIX 3.2.3, when i started working with it - ~1993) to one of the most widely spread and most standard-adhering Unixes at all (5L and above). If you buy hardware from IBM (the POWER6 and POWER5 processors were by far the fastest processors of their times, so many companies did exactly that) you will have to use either Linux or AIX and most companies used AIX in this case.

I hope we have sorted out the misunderstandings.

bakunin

I'm surely going to read at least some of them. :slight_smile:
Thank you for all the info.

As I wrote in another message, I'm a scripting newbie, and shells (well, bash and a very little more) are only my latest hobby. So I just have to learn. Thanks again. :slight_smile:

As for AIX, I know its importance and diffusion on high level systems... that are out of my reach. :wink:

--
Bye

I'm a she and a novice with the scripting, but I've been able to utilize it to create scripts that are helpful to me in managing my DB2's. It's mostly the type of stuff where I list the database directory and loop through the results to take some action (take an image copy, make a database configuration change, etc ). With help from others I've managed to learn just what I need to know in order solve particular problems and each time I look to solve a problem I learn a little more. I support DB2 across a variety of platforms including Redhat Linux on IBM z/Series, AIX on IBM P/series and some Redhat on x86 type hardware which is why I didn't list one even though it is a forum recommendation. I always like it if whatever I come up with will work the same across all the environments and I guess it may just be that our admins have installed support for multiple kernels on everything, but both of your solutions work great in all the places I tested. Lem, I like your solution because it felt like something I could easily understand and implement right away. I also appreciate what you offer bakunin because I don't exactly understand it and you took the time to really explain it so as I look up everything you did I think it will help me expand a little. I appreciate you both taking the time to educate!