Tuesday, January 27, 2009

Bash coolness

There is a clever feature in bash, in that you can do a lot of manipulations while accessing a variable. Note that I always use "clever" in a pejorative sense, but while this is clever (argh) it is also helpful to me. I find that I, like all users, will tolerate a little cleverness if it gets my work done.

In this case, it's the substitution features that get my attention.
For variables:

${VAR:-zzz} returns $VAR, or "zzz" if $VAR is empty
${VAR//x/y} returns $VAR after replacing all "x" with "y"
${VAR:=zzz} returns $VAR or "zzz" if VAR is unset, and assigns VAR (ick)

And of course the coolest version is the $() operator (AKA: command substitution), which used to be done with ugly backticks. This runs a command and returns the output of the command into a variable:

$(echo $fname| cut -d. -f1)
$(echo $(basename $fname) | cut -d -f1)

Which leads to this kind of "clever" coding:

dest=${DESTDIR:-/tmp}/$(echo $(basename ${source// /_})| cut -d. -f1|cut -d= -f1).avi

Which is a pure evil incantation that takes a filename ($source), prefixes it with the destination directory (which defaults to /tmp), strips the path off of it with basename, passes that to a cut filter to remove all dotted suffixes (leaving a raw filename) and then cuts off any suffix that has a "=" preceding it.

The result of passing a source like /aaa/bbb/ccc/ddd=12312.mov.tmp would be a string like /tmp/ddd.avi.

That's evil. It happens to be handy for a transcoding script of mine, but it's pure evil nonetheless. If I come across code like this in the future, I'll want to claw my eyes out.

But the substitution thing is handy.

It doesn't have to be in a single line. I think "one effect per line" and "one trick per line" are pretty good bash programmer rules. One shouldn't try to reach a maximum clever trick density. Really.