printf возвращает несколько копий

#bash #macos #printf

#bash #macos #printf

Вопрос:

В OSX High Sierra bash printf , похоже, ведет себя ошибочно. Рассмотрим:

 printf "[%s]" "x"
  

ВОЗВРАТ

[x]

все хорошо … но:

 printf "[%s]" "x" "y"
  

ВОЗВРАТ

[x][y]

вместо просто [x] !!

не говорите мне: не предоставляйте больше параметров. Я не знаю, как будет выглядеть формат, когда он будет передан мне, но у меня есть параметры

документы не рассматривают это прямо, просто заявляя:

Строка формата используется повторно так часто, как это необходимо для удовлетворения аргументов. Любые дополнительные спецификации формата оцениваются с нулем или нулевой строкой.

это сломано?

Комментарии:

1. Это не ошибка, а особенность

2. Что значит «это передано мне»? В этом примере этого нет. Можете ли вы показать, с чем вы имеете дело?

3. Это не специфичная функция macOS.. Это bash особенность в целом..

4. » Строка формата используется повторно так часто, как необходимо для удовлетворения аргументов. » именно поэтому это происходит. К тому времени, когда printf будет достигнут конец вашей строки формата, все еще останутся некоторые неиспользуемые аргументы, поэтому printf начните сначала с начала строки формата.

5. @melpomene, я думал, что это будет вести себя как оригинальный printf из C!

Ответ №1:

Из утилит posix printf:

  1. Операнд формата должен использоваться повторно так часто, как это необходимо для удовлетворения операндов аргумента.

Это точно означает, что строка формата повторяется столько раз, сколько требуется для перебора всех аргументов. Именно так и предполагалось работать, и это одна из самых полезных функций printf.

Вы хотите повторить символ ‘#’ 10 раз? Нет ничего проще:

 printf "#%.0s" $(seq 10)
# will expand to:
printf "#%.0s" 1 2 3 4 5 6 7 8 9 10
# is equivalent to:
printf "#%.0s#%.0s#%.0s#%.0s#%.0s#%.0s#%.0s#%.0s#%.0s#%.0s" 1 2 3 4 5 6 7 8 9 10
  

%.0s Будет выводить нулевой символ из строки, поэтому он будет выводить нулевой символ, так и будет.. ничего не печатать. Таким образом, # повторяется столько раз, сколько имеется аргументов.

У вас есть массив, и вы хотите напечатать все элементы массива, разделенные новой строкой? Нет ничего проще:

 arr=(1 2 3 value1 test5 text7)
printf "%sn" "${arr[@]}"
  

Комментарии:

1. вау. хорошо. это противоречит здравому смыслу, но я вижу, насколько это ценно. это также, к сожалению, означает, что у меня не может быть дополнительных параметров, поэтому, если я получу строку формата, мне теперь нужно пойти посчитать ссылки в ней и убедиться, что передано правильное количество параметров. было бы проще, если бы это работало как оригинальный printf в C, где он просто игнорирует дополнительные параметры

Ответ №2:

Насколько я понимаю, работает так, как указано в этом предложении документации:

Строка формата используется повторно так часто, как это необходимо для удовлетворения аргументов.

В вашем случае у вас есть 2 аргумента («y» и «z») и только 1 format string ([%s]), поэтому он используется повторно (т.е. используйте одно и то же для каждого аргумента).

Он повторяет список аргументов, и когда он достигает format string конца списка, он начинается с начала:

Команда:

 printf "[%s](%s)" "x" "y" "z" "a" 
  

Выводит:

 [x](y)[z](a)
  

Комментарии:

1. Я понял, что это предложение означает, что printf "%s %s" "a" будет печатать «a a», что является обратным

2. @ekkis Это рассматривается во второй части: » Любые дополнительные спецификации формата оцениваются с нулем или нулевой строкой. » Если у вас слишком мало аргументов для строки формата, предполагается, что они равны 0 (для чисел) или пустой строке (для %s).