Seeing Odd Behavior from printf

Problem

Your script is giving you values that don’t match what you expected. Consider this simple script and its output:

$ bash oddscript
good nodes: 0
bad nodes: 6
miss nodes: 0
GOOD=6 BAD=0 MISS=0
$
$ cat oddscript
#!/bin/bash -
badnode=6

printf "good nodes: %d
" $goodnode
printf "bad nodes: %d
" $badnode
printf "miss nodes: %d
" $missnode
printf "GOOD=%d BAD=%d MISS=%d
" $goodnode $badnode $missnode

Why is 6 showing up as the value for the good count, when it is supposed to be the value for the bad count?

Solution

Either give the variables an initial value (e.g., 0) or put quotes around the references to them on printf lines.

Discussion

What’s happening here? bash does its substitutions on that last line and when it evaluates $goodnode and $missnode they both come out null, empty, not there. So the line that is handed off to printf to execute looks like this:

printf "GOOD=%d BAD=%d MISS=%d
" 6

When printf tries to print the three decimal values (the three %d formats) it has a value (i.e., 6) for the first one, but doesn’t have anything for the next two, so they come out zero and we get:

GOOD=6 BAD=0 MISS=0

You can’t really blame printf, since it never saw the other arguments; bash had done its parameter substitution before printf ever got to run.

Even declaring them as integer values, like this:

declare -i goodnode badnode missnode

isn’t enough. You need to actually assign them a value.

The other way to avoid this problem is to quote the arguments when they are used in the printf statement, like this:

printf "GOOD=%d BAD=%d MISS=%d
" "$goodnode" "$badnode" "$missnode"

Then the first argument won’t disappear, but an empty string will be put in its place, so that what printf gets are the three needed arguments:

printf "GOOD=%d BAD=%d MISS=%d
" "" "6" ""

While we’re on the subject of printf, it has one other odd behavior. We have just seen how it behaves when there are too few arguments; when there are too many arguments, printf will keep repeating and reusing the format line and it will look like you are getting multiple lines of output when you expected only one.

Of course this can be put to good use, as in the following case:

$ dirs
/usr/bin /tmp ~/scratch/misc
$ printf "%s
" $(dirs)
/usr/bin
/tmp
~/scratch/misc
$

The printf takes the directory stack (i.e., the output from the dirs command) and displays the directories one per line, repeating and reusing the format, as described earlier.

Let’s summarize:

  • Initialize your variables, especially if they are numbers and you want to use them in printf statements.

  • Put quotes around your arguments if they could ever be null, and especially when used in printf statements.

  • Make sure you have the correct number of arguments, especially considering what the line will look like after the shell substitutions have occurred.

  • If you don’t need the special formatting that printf offers (e.g., %05d), consider using a simple echo statement.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.214.155