Shell Tricks
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