Friday, December 22, 2006

BASH Hacks: Using 2 Comma Delimited Lists to Replicate Simple 2D Array

As we have stated, the data stuctures in BASH are extremely limited. BASH has just introduced a single dimensional array data structure, but it is tricky and hard to use. They have yet to implement a multi-dimensional array data structure, and therefore we are forced to do a lot of trickery in order to replicate the functionality of multi-dimensional arrays. A very simple type of 2 dimensional array that is highly useful for writing test scripts, is a 2 dimensional array with on dimension holding any type of data, and the second dimension relating a boolean value to the values in the first dimension of the array. Say for example we have a bunch of IPs that represent webservers in a cluster, and we're writing a script to test to see if the webservers are up or down. It would come in handy to know wether the last time through the loop the servers were up or down, so we might want an array like this:












192.168.1.1192.168.1.2192.168.1.3
110


Unfortunatly with BASH, this isn't possible. To replicate the simple two dimensional array of this type I have developed a little bit of code that makes extensive use of the Comma Delimited list code that I wrote about in a previous post: BASH Hacks: The Comma Delimited List. For this solution we implement 2 of these lists, the first list holds all of the variables that you are going to run a series of actions on. The second list will be populated by values from the first list that fail these actions or tests, and each item in this list will be equivilant to having a value of "0" in the boolean dimension of the simple 2D array, and conversely a lack of a value on this list is equivilant to a "1" in the boolean dimension. This is a template of the code that I use:

#!/bin/bash
###################################
## 2commas.sh
##
## A template for implementing 2 comma
## delimited lists to replicate the functionality
## of a simple 2D array
###################################

#######VARIABLE DEFINITIONS########
LIST=1,2,3,4,5

# We just initialize this variable here, it won't be used untill much later
DOWNLIST=''
###################################

# loop continuously
while [ 1 ]
do

# At the beginning of every cycle, tack a trailing comma to the end of the list
LOOPVAR=${LIST},

# Loop through the contents of the comma delimited list
while echo $LOOPVAR | grep \, &> /dev/null
do

# grab the first server name out of the comma-delimited list
LOOPTEMP=${LOOPVAR%%\,*}

# remove the first server name from the LOOPVAR comma-delimited list
LOOPVAR=${LOOPVAR#*\,}

if <your test>
then

## possibly some actions here
## possibly not

# if it's on the downlist, take it off and do some stuff
if echo $DOWNLIST | grep $LOOPTEMP &> /dev/null
then

## Some actions
## maybe no actions
## who knows?

# Initialize the NEWDOWNLIST variable,
# which is a temp var that will hold the downlist minus the now up server
NEWDOWNLIST=''

# This loop will take the now up server off the downlist
while echo $DOWNLIST | grep \, &> /dev/null
do

# grab each value in the downlist from the comma delimited list
DOWNLOOPTEMP=${DOWNLIST%%\,*}

# trim the value we just grabbed from the downlist
DOWNLIST=${DOWNLIST#*\,}

# This variable will be empty if the DOWNLOOPTEMP
# variable is different than the LOOPTERM variable
# if they are the same the variable will contain the value of DOWNLOOPTEMP
CONDITION=$(echo ${DOWNLOOPTEMP} | grep ${LOOPTEMP})

# If the variable is empty the value stays on the downlist
# and we add the server to the new list
if [ -z $CONDITION ]
then

# add the server to the new list
NEWDOWNLIST=${NEWDOWNLIST}${DOWNLOOPTEMP},

fi

done

# Set the downlist variable to the value of the New downlist variable
DOWNLIST=${NEWDOWNLIST}

fi

# If the test fails then
else

# This variable will be empty if the DOWNLIST variable
# doesn't contain the LOOPTEMP variable
# otherwise the value of the variable will be the value of the DOWNLIST variable
CONDITION=$(echo ${DOWNLIST} | grep ${LOOPTEMP})

# If the above variable is empty, the value needs to be added to the DOWNLIST
# and some actions performed, otherwise we already noted that it's down, you might
# still want to do some actions here though
if [ -z $CONDITION ]
then

# Add the value to the downlist
DOWNLIST=${DOWNLIST}${LOOPTEMP},

## maybe do some more actions here if you want

fi

fi

done

done

exit 0


For some reason Blogger doesn't respect any attempt on my part to use tabbing, so this code looks like crap, appologies for this. Unless i use the pre tags it won't work, so when i get an elegant solution for tabbing with blogger my script code is going to look pretty nasty. Appologies.

1 comment:

Unknown said...
This comment has been removed by the author.