2

In my bash script I'm including an array of other files required by the program. I then print those in the help description. When I used printf for their output, I got results I was not expecting. I have read that the form ${array[@]} is generally preferred as the default for expansion, so I started with that.

My array declaration:

 scriptDependencies=("script1.sh" "script2.sh")

And the (initial) printf command:

printf "Dependencies: %s\n" "${scriptDependencies[@]}"

What I got as output:

 Dependencies: script1.sh
 Dependencies: script2.sh

Although I believe I understand a basic difference between the subscripts '@' and '*' to be all individual elements vs all elements grouped together, I was not expecting two separate lines to print.

When I switched the printf command to use the ${scriptDependencies[*]} form, a single line (closer to what I desired) was printed:

 Dependencies: script1.sh script2.sh

Is this expected behavior of printf, and of the subscripts? Or does it point to a problem with printf?

I'm using GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin15).

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
tim.rohrer
  • 246
  • 3
  • 12
  • If you want to print an array's contents in unambiguous form, consider: `printf 'Dependencies: '; printf '%q ' "${scriptDependencies[@]}"; printf '\n'` -- it's more to write, but it means that `array=( "foo bar" )` and `array=( foo bar )` each have distinct output -- and that `array=( $'foo\nbar' )` will similarly get sane treatment. – Charles Duffy Sep 25 '16 at 18:12
  • If you don't care as much about formatting control, you can also use `declare -p scriptDependencies` – Charles Duffy Sep 25 '16 at 18:13
  • Perhaps I should take this to chat? I'm not (so far) able to wrap my little brain around either of your comments, but I've tested both. For the %q format, one of the strings I have in the dependencies array includes " (v2)". When I use %q, the space and the parens have the escape seq added. I don't understand what makes that unambiguous? The declare -p scriptDependencies results in an output of: declare -a scriptDependencies='([0]="script1.sh" [1]="script2.sh")' I get that you mentioned these because there is goodness, but I don't understand. So much to learn, so little time :) – tim.rohrer Sep 25 '16 at 20:45
  • 1
    Re: `%q` -- the output is quoted in such a way that you could copy and paste it back into a shell command line, and it would be interpreted as itself -- that is, all as data, not syntax. – Charles Duffy Sep 25 '16 at 22:01
  • 1
    ...and with respect to `declare -p scriptDependencies`, that gives you a shell command you can run that will *exactly* reproduce the given variable, including aspects of its value that aren't obvious (like the indexes given to values -- arrays in bash can be sparse, which is part of why assigning to an array by index based on the count of items it contains is liable to be buggy). – Charles Duffy Sep 25 '16 at 22:03

2 Answers2

9

This is documented and expected behavior. If there are more strings passed to printf than a format string can handle, that format string will be repeated.

"${array[@]}" expands to a shell word per array element. Thus, for an array with two elements, two arguments to printf will be passed; if the format string only has one placeholder (only one %s), then it will be repeated.

By contrast, "${array[*]}" (with the quotes!) will expand to only one argument (with the first character of IFS, a space by default, inserted between each element).


Bash is required to do this by POSIX specification, emphasis added below:

  1. The format operand shall be reused as often as necessary to satisfy the argument operands. Any extra c or s conversion specifiers shall be evaluated as if a null string argument were supplied; other extra conversion specifications shall be evaluated as if a zero argument were supplied. If the format operand contains no conversion specifications and argument operands are present, the results are unspecified.

Consequently, this behavior is portable to all POSIX-compliant shells.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
2

This is expected: from help printf:

The format is re-used as necessary to consume all of the arguments. If there are fewer arguments than the format requires, extra format specifications behave as if a zero value or null string, as appropriate, had been supplied.

gniourf_gniourf
  • 44,650
  • 9
  • 93
  • 104
  • 1
    Very cool. In my system help printf doesn't describe this, but the man page says basically the same thing. But, I'm not sure I would have appreciated what that is saying without having experienced the behavior first hand. Now I'm looking at options to print each dependency on one line without form-feed after the word Dependencies. – tim.rohrer Sep 25 '16 at 18:30