All about printf

In my last article, "Fancy Tricks for Changing Numberic Base", I explored the surprising ability of the Linux shell to convert numeric bases on the fly, including this sweet little snippet that converts FF hexadecimal into decimal notation:


$ echo $(( 0xFF ))
255

And, I discussed how you even could use the handy printf command within scripts too, such as this command to display decimal numbers in octal and hexadecimal:


$ printf "octal: %o\nhex: %x\n" 42 42
octal: 52
hex: 2a

It's pretty neat stuff, but to be honest, I rarely find myself needing to convert numeric bases nowadays, so it's really something I file under "funky shell tricks". Your experience may be different, so it's still well worth learning anyway.

In this article, I thought it would be interesting to take a closer look at the printf command, because it is so darn powerful, but before going there, here's a quickie: some neat ways you can make your if-then statements be more succinct.

If/Then Statements

If you're like me, then you find yourself frequently writing conditional statement blocks in your shell scripts. Um, I mean:


if [ you're like me ] ; then
   you find yourself...

Well, you get the idea. In fact, conditional expressions are where sequences of code turn into more sophisticated programs, whether they're a half-dozen lines long or hundreds of lines.

A typical conditional expression actually might look like this:


if [ $(date +%w) -eq 0 ]; then
   echo "It's Sunday"
else
   echo "It's not Sunday"
fi

This is clear and readable, but it sure takes up a lot of vertical space in a shell script.

Fortunately, there are some ways you can tighten up things by using the && and || notations in your shell scripts.

The && notation means if what's invoked prior to the && ends with a success return code, do what's subsequent—for example:


test $(date +%w) -eq 0 && echo "Sunday"

If it's Monday afternoon when I run this code, I'll get no output, and the echo statement isn't even evaluated. But if it's Sunday, the above command will output appropriately.

The || notation offers the same basic functionality but with the opposite logic: if the return code of the command prior to the || returns a fail (non-zero) return code, then the subsequent command will be invoked:


test $(date +%w) -eq 0 || echo "It's not Sunday yet"

You also can make this even more succinct by using the [] notational shortcut for a test—just remember to include the closing ] to ensure it's all well formed:


[ $(date +%w -eq 0 ] || echo "it's not Sunday yet"

The biggest limitation with this notation is that there's really no reliable and properly interpreted way to add an else clause.

You can try something like this:


cmd1 && cmd2 || cmd3

But because of precedence interpretation, it's likely to have cmd3 invoked if either cmd1 or cmd2 have a non-zero return code, which makes it functionality different from this:


if cmd1 ; then
  cmd2
else
  cmd3
fi

______________________

Dave Taylor has been hacking shell scripts for over thirty years. Really. He's the author of the popular "Wicked Cool Shell Scripts" and can be found on Twitter as @DaveTaylor and more generally at www.DaveTaylorOnline.com.