Это поведение является следствием двух правил:
Когда вы передаете printf
больше аргументов, чем строка формата содержит заполнители, строка формата повторяется до тех пор, пока не будут использованы все аргументы. С форматной строкой, имеющей только один заполнитель, это означает, что она повторяется один раз для каждого последующего аргумента.
Когда вы не заключаете в кавычки расширения параметров, они подвергаются разделению слов (создание отдельного слова для содержимого по обе стороны от каждого символа в IFS
) и расширению глобуса (заменяя эти слова списком имен файлов). которым они соответствуют, когда интерпретируются как globs, если такие имена существуют), что приводит к переменному числу слов оболочки, каждое из которых передается в качестве отдельного аргумента printf
.
Таким образом, TESTVAR='something fishy'; echo $TESTVAR
со значением по умолчанию IFS
становится точным эквивалентом echo "something" "fishy"
, который печатает something fishy
, поскольку echo
разделяет каждый аргумент пробелом.
Напротив, printf %b $TESTVAR
становится printf %b "something" "fishy"
, который использует %b
для форматирования something
, и снова для форматирования fishy
; ничего там не вставляет пробел, поэтому вы не получите пробелов на выходе. (Если бы вместо этого вы сделали printf '%b ' $TESTVAR
, вы бы увидели вставленные пробелы).
Наконец, printf %b "$TESTVAR"
работает printf %b "something fishy"
; пробел сохраняется, поскольку он является литеральной частью третьего аргумента, поэтому строка формата %b
оценивается только один раз по отношению ко всему аргументу something fishy
с уже включенным пробелом.
Урок этой истории: Всегда цитируйте свои расширения. См. Также BashPitfalls # 14 , подробно описывающий, как echo $foo
сам по себе глючит, если не указан echo "$foo"
.