0

I have a string: string="foo=bar boo=far rab=oof raf=oob"

I want to replace all white-space within the string with a newline character: string=${string// /$"\n"}

When I use printf, bash prints:

~$ printf "%s" "$string"
foo=bar\nboo=far\nrab=oof\nraf=oob

However, when I mistyped the command as printf %s""$string, I got:

~$ printf %s""$string
foo=bar
boo=far
rab=oof
raf=oob

What is the difference in printf "%s" "$string" and printf %s""$string that printf will only interpret newline characters in one of the commands?

pntha
  • 39
  • 8

1 Answers1

3

$"\n" looks for a translation of \n in the current locale, but as it doesn't find anything, it just returns \n (see How to add localization support to your bash scripts (BashFAQ/098) for details).

  1. printf %s "$string" (quotes around %s aren't needed) takes the contents of the $string and prints it as is.

  2. printf %s""$string concatenates %s with an empty string and the contents of the variable. \n thus gets into the template and is interpreted as a newline.

You can use set -xv to make the shell show you how it interprets the commands and variables.

Creating a printf template from unsecured strings is dangerous. I'd recommend a different way:

s=${string// /$'\n'}
printf %s "$s"

The $'\n' expands into a real newline character, so $s will contain actual newlines. You can then print it directly.

Another way would be

printf '%s\n' $string

without changing the value of $string. Non-quoted string gets word split, and each resulting word is printed using the template which adds a newline to it.

choroba
  • 231,213
  • 25
  • 204
  • 289