For someone that used to be very vocal about hating shell scripting, I seem to be building more and more tools related to it every day. The latest is caller (from “man bash”):
caller [expr]
Returns the context of any active subroutine call (a shell function or a script executed with the . or source builtins). Without expr, caller displays the line number and source filename of the current subroutine call. If a non-negative inte‐ ger is supplied as expr, caller displays the line number, subroutine name, and source file corresponding to that position in the current execution call stack. This extra information may be used, for example, to print a stack trace. The current frame is frame 0. The return value is 0 unless the shell is not executing a subroutine call or expr does not correspond to a valid position in the call stack.
This means that if your bash code makes heavy use of functions, you can get the call stack back out. This turns out to be really handy for things like writing testing scripts. I recently added some more unit testing to devstack-gate, and used this to make it easy to see what was going on:
# Utility function for tests function assert_list_equal { local source=$(echo $1 | awk 'BEGIN{RS=",";} {print $1}' | sort -V | xargs echo) local target=$(echo $2 | awk 'BEGIN{RS=",";} {print $1}' | sort -V | xargs echo) if [[ "$target" != "$source" ]]; then echo -n `caller 0 | awk '{print $2}'` echo -e " - ERRORn $target n != $source" ERRORS=1 else # simple backtrace progress detector echo -n `caller 0 | awk '{print $2}'` echo " - ok" fi }
The output ends up looking like this:
ribos:~/code/openstack/devstack-gate(master)> ./test-features.sh test_full_master - ok test_full_feature_ec - ok test_neutron_master - ok test_heat_slow_master - ok test_grenade_new_master - ok test_grenade_old_master - ok test_full_havana - ok
I never thought I’d know this much bash, and I still think data structure manipulation is bash is craziness, but for imperative programming that’s largely a lot of command calls, this works pretty well.