Shell Tricks

Printer-friendly version

Coding in sh or bash can be challenging. Here are some tricks I've learned over the years

Extracting fields from lists

I have a list of items in $LIST; each item is separated from each other item by a comma, and individual items may contain spaces.

~ $ LIST="abc,def ghi,jkl"
~ $ echo [$LIST]
[abc,def ghi,jkl]

I want an array, with one element per item in my list. I can't just

~ $ ARRAY=($LIST)

because the shell will break the list into items, not at the commas, but at the spaces, giving

~ $ echo There are ${#ARRAY[@]} elements in ARRAY
There are 2 elements in ARRAY
~ $ for element in "${ARRAY[@]}" ;
> do
> echo ARRAY element contains [$element]
> done
ARRAY element contains [abc,def]
ARRAY element contains [ghi,jkl]
~ $

To break the list at the comma, we have to do something special, we have to (temporarily) set IFS to a comma, before we load our ARRAY.

~ IFS=, ARRAY=($LIST)
~ echo There are ${#ARRAY[@]} elements in ARRAY
There are 3 elements in ARRAY
~ $ for element in "${ARRAY[@]}" ;
> do
> echo ARRAY element contains [$element]
> done
ARRAY element contains [abc]
ARRAY element contains [def ghi]
ARRAY element contains [jkl]
~

Testing for Numeric

While working with the limited, basic shell on my IP04, I encountered a situation where I had to validate that an argument was numeric. I made a couple of attempts at a solution before settling on a negative test.

The IP04 platform supports a number of standard Unix tools (courtesy of Busybox), stripped down to their bare essentials, and I settled on test(1) and tr(1) as components of my solution.

Instead of testing the field to determine if all the characters are numeric, I use tr(1) to eliminate the digit characters in the field. If there's anything left of the field after I do this, then the field was not "numeric" (digits only). The only exception is an empty field, but this I can test for as well.

So, my test for numeric fields becomes:

  [ -n "$arg" ] && [ -z "`echo $arg | tr -d '[0-9]'`" ]

And, in use, it becomes:

  for arg in  111 123 1 999 face f444 4fff ""
  do
    if [ -n "$arg" ] && [ -z "`echo $arg | tr -d '[0-9]'`" ]
    then
      echo '"'$arg'"' IS numeric
    else
      echo '"'$arg'"' IS NOT numeric
    fi
  done 

Articles: 
System Management: