71

I'm trying to use printf to format some pretty output in a bash script

e.g.:

-----------------------  
| This is some output | 
-----------------------

But I've stumbled over some behavior I don't understand.

$ printf "--"

gives me the error:

printf: usage: printf [-v var] format [arguments]

and

$ printf "-stuff"

results in

-bash: printf: -s: invalid option

So apparently printf thinks I'm trying to pass some arguments while I'm not.

Meanwhile, completely by accident, I've found this workaround:

$ printf -- "--- this works now ----\n"

gives me

--- this works now ----

Can anyone explain this behavior?

Paulo Tomé
  • 3,782
  • 1
    See also http://unix.stackexchange.com/questions/11376/what-does-double-dash-mean – manatwork Oct 17 '11 at 11:51
  • Out of intereset, are there any implementations of echo that would fail when doing echo ------------? Most only support -n (no trailing newline), -e (interpret backslash-escaped chars) and possible -E (do NOT interpret them) and do not error out when other option-like arguments are encountered, right? (EDIT: GNU's /bin/echo also supports --help and --version.) – janmoesen Oct 18 '11 at 06:34

4 Answers4

78

The -- is used to tell the program that whatever follows should not be interpreted as a command line option to printf.

Thus the printf "--" you tried basically ended up as "printf with no arguments" and therefore failed.

Kusalananda
  • 333,661
sr_
  • 15,384
  • 33
    In other words, to print -- you can run printf -- --. – l0b0 Oct 17 '11 at 12:14
  • 2
    ... and printf -- is the same as printf (you get the same message) – Peter.O Oct 17 '11 at 14:54
  • 4
    Note that printf -- $fmt is not portable. On busybox 1.30.1, printf -- '%s\n' hello yields --. See also: https://pubs.opengroup.org/onlinepubs/009695399/utilities/printf.html – kelvin Nov 17 '19 at 22:18
  • 2
    @AlexanderShukaev My bad, I tested it on LineageOS and now I see that it uses mksh in adb shell instead of busybox. It works normally with busybox printf -- '%s\n' hello. The point about portability still stands though. – kelvin Apr 26 '20 at 03:53
  • @kelvin - Why would printf -- '%s\n' hello yields --? It is not shown in that man page. – midnite Apr 19 '22 at 17:37
  • @midnite "Why would printf -- '%s\n' hello yields --? It is not shown in that man page." I had tested that command on adb shell and that was the output. If you want to know why exactly that happens, you'd probably have to read the source code of the mksh version used by adb shell. – kelvin Apr 19 '22 at 19:56
  • @kelvin - I see. Thanks for reply. So this seems to be a special behaviour of mksh. It does not happen to most of the other shells, e.g. bash. – midnite Apr 19 '22 at 20:15
  • @kelvin - Just check in from my LineageOS, which adb shell echo "$SHELL" shows /system/bin/sh. It seems that its printf is treating its $1 as formatting string ALWAYS. adb shell printf aa bb cc gives aa. adb shell printf -v bb cc gives -v. adb shell printf %s bb cc gives bbcc. adb shell printf %c bb cc gives bc. Note that I by purpose miss out the quotation marks. – midnite Apr 21 '22 at 15:01
  • @midnite "Just check in from my LineageOS, which adb shell echo "$SHELL" shows /system/bin/sh. It seems that its printf is treating its $1 as formatting string ALWAYS." Interesting; when I read your first comment I had already forgotten the reason for this behavior, but indeed always treating $1 as the format (just like printf(3p)) seems to be it. Thanks for the details. By the way, the same behavior happens on the built-in "Terminal Emulator" on LineageOS, which appears to use the same shell (see the output of sh -v). – kelvin Apr 22 '22 at 17:28
45

-- is being interpreted as an option (in this case, to signify that there are no more options).

A format string should always be included when using printf to prevent bad interpretation. For your particular case:

printf '%s\n' '-----------------------'
Chris Down
  • 125,559
  • 25
  • 270
  • 266
12

There are differences between printf builtin and /usr/bin/printf, the second one do "what you mean" without these annoying errors.

printf "-----"             # error
printf -- "-----"          # ok
/usr/bin/printf "-----"    # ok
/usr/bin/printf -- "-----" # ok
BOC
  • 221
3

POSIX provides the option of using octal encoding.

 printf "--"

can become:

printf "\055-"

This is a portable way to avoid the ambiguity of whether -- is being used as a format string or as a marker for the end of options.

jhnc
  • 255