Thursday, May 20, 2010

Bash101: Convert colon-delimited string into an array

A common bash scripting task that I face is how to convert a non-space or non-tab delimited string into an array. The challenge is that when you initialize an array with a set of values, the values are typically delimited by spaces or tabs. However, many of the inputs that I have to parse for storing in an array are colon, semi-colon or pipe delimited. For example, in my Zone Manager script, I like to pass multivalued strings into parameters. For example, the following -S flag passes a pipe delimited string.

-S "ssh|cron|syslogd|svc:/network/ftp:default"

Here is one way that I can store that string into an array.
read -r -a services <<< $(echo ${OPTARG} | sed \
   -e "s/  /_TAB_/g" \
   -e "s/ /_SPC_/g" \
   -e "s/|/ /g")
for (( i=0; i< ${#services[*]}; i++ ))
   services[${i}]=$(echo ${services[${i}]} | \
      sed -e "s/_SPC_/ /g" -e "s/_TAB_/      /g")

Although my example string didn't include any spaces or tabs, it could have.  Thus, in this example I converted spaces to "_SPC_" and tabs to "_TAB_" and then converted the pipe symbol (|) to spaces.  That way the array will be parsed according to its native delimiter, the space and properly store each value into an array entry.  Then after the array is populated with the right fields, I go back and revers the space and tab conversion to restore their values to their original state.  Note that you can use any unique string that you like for the temporary replacement values of the space and tab characters.  I just used _SPC_ and _TAB_ for simplicity.

Have a great day!



Brett said...

Ugh, that's a lot of seds. This can all be done with the help of IFS:

IFS="[|TAB ]" read -ra service <<< $(echo ${OPTARG})

where TAB is a literal tab char (^v then tab).

Brad Diggs said...

Thanks Brett. I originally tried IFS but could not get it to work. Not sure if it is a bash version issue or what. That is why I had to resort to sed.