Error handling in bash

I’ve been learning about approaches to error handling in bash. I found Error handling in BASH, Exit Shell Script Based on Process Exit Code, Writing Robust Bash Shell Scripts and Bash: Error handling all of which contained a nugget of useful information.

Particularly I learned about $LINENO, set -e (equiv: set -o errexit), set -o pipefail, set -E, set -u (equiv: set -o nounset), set -C (equiv: set -o noclobber), #!/bin/bash -eEu, trap, shopt -s expand_aliases, alias, $PIPESTATUS, subshells, unset, and more.

If you call exit without specifying a return code then $? is used, I didn’t know that.

I found this code snippet that demos a relatively race-condition free method of acquiring a lock file:

if ( set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null; 
then
   trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT

   critical-section
   
   rm -f "$lockfile"
   trap - INT TERM EXIT
else
   echo "Failed to acquire lockfile: $lockfile." 
   echo "Held by $(cat $lockfile)"
fi 

Unix command to format a number of bytes as a human readable value

It took me a while, but I finally figured out how to print a number from a bash script properly formatted with commas as thousand’s separators. For those like me who weren’t in the know, the magical incantation is:

  printf "%'d" 123456

That will format 123456 as 123,456. Much easier to read when you’re dealing with large numbers such as the sizes of files in gigabytes.

So now if I could only find the Unix command that took a number of bytes and turned it into an approximate value with GB or MB suffixes.

tr

I learned about the ‘tr’ Unix command today. It’s for translating text in streams. The particular example was:

  echo | tr '012' '001'

And I didn’t really understand what that did, but now I do. Basically the ‘echo’ part will echo a new line character, which is octal 012. Then tr will read its input stream and read that new line. It then has a rule to translate 012 (new line) to 001 (Ctrl+A), which it does. So basically it’s just a way of getting a Ctrl+A character in a stream. If you use Ctrl+A as your regular expression delimiter you’re unlikely to have a collision in the expression itself.

Environment Variables and Secure Programming for Linux

I read the Environment Variables section of Secure Programming for Linux and Unix HOWTO and learned about the IFS environment variable.

I also read CS 15-392 Secure Programming – Environment Variables.

The IFS environment variable is the “internal field separator” and it is typically space, tab, new line. I.e. white space used to separate fields. So in bash you can delete the IFR variable and it will default to ” \t\n” or you can set it explicitly to that value. So that explains why I found a script that unset the IFR variable — it’s a secure programming practice.

I’ve set up a new file server

I’ve been having some fun over the last day or two looking over all my old files. I’ve got files that go back as far as 1999 in my archives. I’ve found my old blog database and associated files, so I hope to get that back up again soon, and I found some old code that I’ve been looking for (I don’t want to have to write it again!).

So my new file server has 6TB of storage as 3 x 2TB partitions. I can fit all my data in 1.3TB of space, so I’m planning to have one file share, and then a backup of that onto another partition. I have 10,174,633 files in my archive folder, and many more in my media, download and home folders. I might publish some more stats once du -s has finished processing. :)

I’m running Ubuntu 10.04 LTS Server as my file server. I tried to setup the Desktop version but it wouldn’t play nice with my nVidia graphics card.