Saturday, January 16, 2016

Bash-ing code

I've been writing a ton of bash scripts lately, and the absence of many high-level language features combined with the lack of a safety net makes it surprisingly difficult for me to quickly write solid code.

But all is not lost! Several great tools have come to my rescue.

The first is ShellCheck, a Haskell program that is straightforward to install on any platform. It not only finds silly mistakes that are difficult to troubleshoot, but it also encourages several best practices.

The second is the Unofficial Bash Strict Mode. Flip a few shell options, modify IFS, and suddenly scripts become much noisier, revealing lots of what's going on behind the scenes in bash.

Next are various hints, tips and tricks for bash debugging. Be sure to dig into the comments and other replies. Lots of gems there. I haven't yet used bashdb, but I'm glad it's there waiting for me.

I do all my other development in Eclipse, so I'm using the ShellEd extension, a older tool that isn't aging well at all, but still does its basic job.

Bash has one terrible "feature" that caught me last week. What do you think the following script will do when passed various input?
#!/usr/bin/env bash
# file: array_test.sh
arr=("$@")
for s in "${arr[@]}"; do
    echo "$s"
done
Try the above code under the following three scenarios:
1: ./array_test.sh one two three
2: ./array_test.sh one two
3: ./array_test.sh one
There's a surprise waiting!  Go ahead, try it. I'll wait. Really, I'll be here when you get back. Promise.

Bash arrays are wonderful, but an array with a single entry behaves the same as a regular variable.  The way to get around this is to always use the array index.  So here's an update of the above code.  Does it perform any different?
#!/usr/bin/env bash
# file: array_test.sh
arr=("$@")
for i in "${!arr[@]}"; do
    echo "${arr[$i]}"
done