I’m actually not a huge fan of shell scripting, in spite of the fact that I’ve been doing it for years, and am fairly adept at it. I guess because the shell wasn’t really intended to be used for programming per se, it has evolved into something that sorta kinda looks like a programming language from a distance, but gets to be really ugly and full of inconsistencies and spooky weirdness when viewed up close. This is why I now recode in Python where appropriate and practical, and just about all new code I write is in Python as well.
One of my least favorite things about Bash scripting is arrays, so here are a few notes for those who are forced to deal with them in bash.
First, to declare an array variable, you can assign directly to a variable name, like this:
myarr=('foo' 'bar' 'baz')
Or, you can use the ‘declare’ bash built-in:
declare -a myarr=('foo' 'bar' 'baz')
The ‘-a’ flag says you want to declare an array. Notice that when you assign elements to an array like this, you separate the elements with spaces, not commas.
Arrays in bash are zero-indexed, so to echo the value of the first element of myarr, we do this:
echo ${myarr[0]}
Now that you have an array, and it has values, at some point you’ll want to loop over it and do something with each value in the array. Almost anyone who utilizes an array will at some point want to do this. There’s a little bit of confusion for the uninitiated in this area. For whatever reason, there is more than one way to list out all of the elements in an array. What’s more, the two different ways act different if they are used inside of double quotes (wtf?). To illustrate, cut-n-paste this to a script, and then run the script:
#!/bin/bash myarr=('foo' 'bar' 'baz') echo ${myarr[*]} echo ${myarr[@]} echo "${myarr[*]}" echo "${myarr[@]}" # looks just like the previous line's output for i in "${myarr[*]}"; do # echoes one line containing all three elements echo $i done for i in "${myarr[@]}"; do # echoes one line for each element of the array. echo $i done
Odd but true. The “@” expands each element of the array to its own “word”, while the “*” expands the entire set of elements to a single word.
Another oddity — to get just a count of the elements in the array, you do this:
echo ${#myarr[*]}
Of course, this also works:
echo ${#myarr[@]}
And the funny thing here is, these two methods do not appear to produce different results when inside of double quotes. I’d be hard pressed, of course, to figure out a use for counting the entire set of array elements as “1”, but it still seems a little inconsistent.
Also note that you don’t have to count the elements in the array – you can count the length of any element in the array, too:
echo ${#myarr[0]}
That’ll return 3 for the array we defined above.
Have fun!