6

To make my code portable, I try to use printf rather than echo. But then

printf "-dogs-cats"

returns an error. A workaround in the present case is:

printf "-";printf "dogs-cats"

But is there a general, portable command (or an option with printf) that will print an arbitrary string as a literal/verbatim, not try to interpret the string as a format?

I work in BSD Unix (on a Mac), but my objective is code that would work in other Unix flavors as well.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jacob Wegelin
  • 1,304
  • 11
  • 16

2 Answers2

11

Use a format specification:

printf '%s' "-dogs-cats"
chepner
  • 497,756
  • 71
  • 530
  • 681
  • I like this answer best as it is applicable to crazy control sequences that one might want to use without the shell interpreting them. – Demitri Oct 25 '17 at 15:02
6

Just use -- after printf to let it know that no more arguments are to come and to consider the string as so:

$ printf -- "-dogs-cats" 
-dogs-cats                    # no new line after this

This is a *NIX-trick that can be used for many other commands. As Bash Reference Manual → 4 Shell Builtin Commands says:

Unless otherwise noted, each builtin command documented as accepting options preceded by ‘-’ accepts ‘--’ to signify the end of the options. The :, true, false, and test builtins do not accept options and do not treat ‘--’ specially. The exit, logout, return, break, continue, let, and shift builtins accept and process arguments beginning with ‘-’ without requiring ‘--’. Other builtins that accept arguments but are not specified as accepting options interpret arguments beginning with ‘-’ as invalid options and require ‘--’ to prevent this interpretation.


Note why this happens:

$ printf "-dogs-cats" 
bash: printf: -d: invalid option
printf: usage: printf [-v var] format [arguments]

This makes printf understand the first part of the string, -d, as an argument.

fedorqui
  • 275,237
  • 103
  • 548
  • 598
  • 1
    was about to post this as answer :D probably also point out that printf doesn't add newline by default – Sundeep Nov 04 '16 at 13:01
  • 2
    Alternately, use a format specification: `printf "%s" "-dogs-cats"` – glenn jackman Nov 04 '16 at 13:05
  • This doesn't work in all cases - try doing `printf -- "/var/log/celery/%n%I.log"` - you would get `I': invalid format character`. I used a combination of your answer and @chepner answer with %s and that worked. – Almenon Apr 20 '20 at 18:31