为什么 shell printf 运行 没有被引用时串在一起?

Why does shell printf run strings together when not quoted?

有人可以解释 shell 脚本中的这种行为吗:

TESTVAR='something fishy'
echo $TESTVAR
something fishy

但是

printf "%b" $TESTVAR
somethingfishy            (space removed)

同时

printf "%b" "$TESTVAR"
something fishy

为什么会这样?

此行为是两个规则的结果:

  • 当您传递 printf 个比格式字符串包含的占位符更多的参数时,将重复格式字符串,直到使用完所有参数。对于只有一个占位符的格式字符串,这意味着它在每个后续参数中重复一次。

  • 当您不引用参数扩展时,它们会经历 word-splitting(为 IFS 中每个字符两侧的内容创建一个单独的词)和 glob 扩展 (如果存在任何此类名称,则将这些单词替换为它们在解释为 glob 时匹配的文件名列表),从而导致可变数量的 shell 个单词,每个单词都作为单独的参数传递给 printf.


因此,具有默认值 IFSTESTVAR='something fishy'; echo $TESTVAR 精确等价于 echo "something" "fishy",它打印 something fishy,因为 echo 分隔每个参数space.

相比之下,printf %b $TESTVAR变为printf %b "something" "fishy",它使用%b格式化something,并再次格式化fishy;那里没有插入 space,因此您不会在输出中得到任何 space。 (相反,如果你做到了 printf '%b ' $TESTVAR,你会看到插入了 space)。

最后,printf %b "$TESTVAR" 运行 printf %b "something fishy"; space 被保留,因为它是第三个参数的文字部分,因此 %b 格式字符串只被评估一次,针对整个 something fishy 参数已经包含 space .


这个故事的教训:总是引用你的扩展。另见 BashPitfalls #14 详细描述 echo $foo 本身是错误的,除非引用为 echo "$foo".