0

I wrote the following script when trying to understand how printf works:

#!/usr/bin/bash

printf "Give me your three preferences.? " read p1 read p2 read p3 printf "%s\n" "${p1}" "${p2}" "${p3}" printf "Just the same as this, \n" printf "%s\n%s\n%s\n" "${p1}" "${p2}" "${p3}" printf "I've found this way to be the easiest, ${p1}\n ${p2}\n ${p3}\n"

By trial-and-error, I figured out that the third way works - though it was not specified this learning resource. I use printf in this way most frequently because it is echo-like. Are there any cases or values of variables where such way of printing values to stdout does not work? Why might I want to avoid such way of using printf?

muru
  • 72,889
  • 1
    If you care about the easiest way, you should stop needlessly using curly braces. e.g. your first printf can and should be written as printf '%s\n' "$p1" "$p2" "$p3". See $VAR vs ${VAR} and to quote or not to quote – cas Aug 10 '23 at 10:03
  • 1
    In the long past, it was easy to derail badly written (C) applications that did last case with printf(3) for the same reason: If the user could provide it a string like %60000s chances it would segfault. – A.B Aug 10 '23 at 12:49

2 Answers2

5

Why might I want to avoid such way of using printf?

As FelixJN mentioned your last printf only has a format in which you include user-supplied data. Try your script and input something like "my first preference is %s". In your last case it would not print the %s but interpret it as format specifier with missing argument (therefore %s replaced with nothing):

$ p1="%s"
$ printf "I've found this way to be the easiest, ${p1}\n"
I've found this way to be the easiest, 

In other languages, C for example, this can be even considered a security vulnerability because it handles wrong format strings not as lenient as Bash does. Known as "format string vulnerability" or "uncontrolled format string".

  • 1
    Also printf "foo $bar" "baz" prints drastically different output depending of bar containing %s or not. – legolegs Aug 10 '23 at 13:04
2

printf commands are built like

printf format [argument]...

I.e. your last options is formally printing a format only and no argument to which that format shall be applied. Which is fine. The advantage of printf is that arguments may be specifically formatted, e.g. padding with zeros or defining a maximum string length.

You want neither of those, but to be honest, echo would be sufficient for that use case.

FelixJN
  • 13,566
  • 1
    echo may be "sufficient" in some cases, but the caveats in Why is printf better than echo? still apply (i.e. you don't generally know how echo will format a string containing user-supplied data). Also notice the user's last command and what would happen if a variable contained certain backslash or % sequences. – Kusalananda Aug 10 '23 at 08:16
  • Printing just the format becomes not so fine if it includes user-supplied data. If for example p1 contains a format specifier the output becomes kinda messed up. – Paul Pazderski Aug 10 '23 at 08:22
  • @Kusalananda but isn't exactly the caveat happing in OPs use case as the shell interprets the variables before the format string is created? e.g. a var="\t" will be shown as 'TAB' in printf $var and as literal \t only in printf %s $var. – FelixJN Aug 10 '23 at 08:25
  • 2
    You're correct, but the user say (paraphrasing) "I use printf this way as it's how echo works". What I commented on is that with echo, you have no real control over the formatting of the output (it depends on the shell's configuration at the time of running the command). With printf, you have several issues with using user-supplied data in the format string (and you should not do this), but the behaviour is at least more predictable (it will fall apart in ways that are not dependent on shell settings). – Kusalananda Aug 10 '23 at 08:38