带参数扩展字符串替换的换行符的 printf 解释

printf interpretation of newline characters with parameter expansion string replacement

我有一个字符串:string="foo=bar boo=far rab=oof raf=oob"

我想用换行符替换字符串中的所有白色-space:string=${string// /$"\n"}

当我使用 printf 时,bash 打印:

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

但是,当我将命令输入错误为 printf %s""$string 时,我得到:

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

printf "%s" "$string"printf %s""$string 有什么区别 printf 只会解释其中一个命令中的换行符?

$"\n" 在当前语言环境中查找 \n 的翻译,但由于没有找到任何内容,它只是 returns \n(请参阅 How to add localization support to your bash scripts (BashFAQ/098) 了解详情)。

  1. printf %s "$string"(不需要 %s 周围的引号)获取 $string 的内容并按原样打印。

  2. printf %s""$string 将 %s 与空字符串和变量的内容连接起来。 \n 因此进入模板并被解释为换行符。

您可以使用 set -xv 让 shell 向您展示它如何解释命令和变量。

从不安全的字符串创建 printf 模板是危险的。 我推荐一种不同的方式:

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

$'\n' 扩展为一个真正的换行符,因此 $s 将包含实际的换行符。然后就可以直接打印了。

另一种方式是

printf '%s\n' $string

不改变 $string 的值。不带引号的字符串进行单词拆分,每个生成的单词都使用向其添加换行符的模板打印。

根据 bash 联机帮助页,您不是用换行符替换,而是用反斜杠和 n 个字符替换:

A double-quoted string preceded by a dollar sign ($"string") will cause the string to be translated according to the current locale. If the current locale is C or POSIX, the dollar sign is ignored. If the string is translated and replaced, the replacement is double-quoted.

(我怀疑您反而想使用 $'' 和两个单引号。)

printf 命令将“\n”解释为换行符的转义序列,但仅在第一个参数中,这就是您的命令中发生的情况:

printf %s""$string