Использование оболочки Bourne "printf %s"
У меня есть простая функция оболочки debug_print, которую я использую для написания больших сценариев оболочки. В общем, я стараюсь писать только Bourne-совместимые скрипты и избегаю Bash-isms. В этом случае Bash-версия моей функции debug_print работает нормально, но я не могу до конца понять, почему моя Bourne-совместимая версия дает сбой. В частности, у меня проблемы с использованием модификатора формата% s с printf.
Я включил свой тестовый скрипт ниже. Функция debug_print отображает строку заголовка с меткой, содержимое ее строки или аргумента файла и, наконец, строку нижнего колонтитула с той же шириной, что и заголовок. Проблемы с отображением строки нижнего колонтитула и начинаются с комментария "Отображение строки нижнего колонтитула...". Следующие две строки без комментариев - это то, что, я считаю, должно работать, но не работает.
Далее следует несколько закомментированных строк под комментарием "Ни одна из этих работ", где вы можете увидеть некоторые из различных тестов / отклонений, которые я использовал, пытаясь выяснить проблему. После этих строк - рабочая версия Bourne и, наконец, рабочая версия Bash.
Я прочитал man-страницы до мельчайших подробностей и перепробовал все возможные варианты форматирования строк, цитирования и использования переменных. Пока что ни одна из этих попыток не работает правильно. Под комментарием "Ни одна из этих работ" все нерабочие команды выводят всю строку вместо, как я полагаю, только числа символов, указанного модификатором ширины поля.
Для определения "совместимости с Bourne" я использую dash как / bin / sh в моей системе, что типично для систем Debian. Тире предназначено для эффективного выполнения сценария, а не интерактивного использования. Согласно man-странице, он стремится к строгой совместимости с Bourne, поэтому я решил, что если мой скрипт работает с dash, то он должен быть достаточно Bourne-совместимым и свободным от ошибок. Кроме того, я признаю, что эта функция не является основной / конечной целью отладочной печати, и, вероятно, существуют многочисленные угловые случаи и области, где ее можно улучшить. Я приветствую все предложения, но я особенно заинтересован в этой проблеме printf. Учитывая, насколько это должно быть просто, кажется, что я, должно быть, совершаю какую-то глупую ошибку, но не могу ее обнаружить.
Вот мой тестовый скрипт debug_print:
#!/bin/sh
#
# Purpose: Debug print function. Outputs delimiting lines and will display
# either the contents of a file or the contents of a variable.
#
# Usage: debug_print label input
# Where label is the title to print in the header bar, usually the name of
# the input variable. Input is either a file on disk to be printed, or,
# if the argument is not a file then it is assumed to be a string and that
# will be displayed instead.
#
# Returns: If two parameters are not provided, returns false, otherwise it
# will always return true.
#
debug_print()
{
local header_bar header_len dashes
# Check for arguments
if [ $# -ne 2 ]; then
printf "Error: debug_print takes two parameters: 'label' and 'input'\n"
return 1
fi
header_bar="-------------------------$1-------------------------"
header_len=${#header_bar}
printf "%s\n" "$header_bar"
# Display either the contents of the input file or the input string
if [ -r "$2" ]; then
cat "$2"
else
printf "%s\n" "$2"
fi
# Display a footer line with the same length as the header line
dashes="------------------------------------------------------------"
printf "%*s\n" "$header_len" "$dashes"
# None of these work
# printf "%${header_len}s\n" "$dashes"
# printf "%${header_len}s\n" "------------------------------------------------------------"
# printf "%5s\n" xxxxxxxxxxxxxxxxxxxx
# printf '%5s\n' "xxxxxxxxxxxxxxxxxxxx"
# xxx="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# printf '%5s\n' $xxx
# This works with dash
# i=$header_len
# while [ $i -gt 0 ]; do
# printf "-"
# i=$(( $i - 1 ))
# done
# printf "\n"
# Working bash version
# printf -v foot_line '%*s' $header_len
# echo ${foot_line// /-}
return 0
}
# Test debug printing
debug_print "Label" "The contents of the debug input..."
Спасибо за любую помощь.
1 ответ
Вы пишете для соответствия POSIX или для соответствия Bourne-shell, это разные вещи.. dash
стремится к строгому соответствию POSIX, а не Bourne.
Кроме того, переменная ширина поля:
printf "%*s\n" "$header_len" "$dashes"
не поддерживаются в стандарте оболочки POSIX.
Чтобы сократить длину строки, вы можете использовать точку и переменную в поле формата:
printf "%.${header_len}s\n" "$dashes"
--редактировать--
В этом томе POSIX.1-2008 не предусмотрено никаких положений, позволяющих указывать ширину и точность полей как
*
так как*
можно заменить непосредственно в операнде формата с помощью подстановки переменных оболочки. Реализации также могут предоставлять эту функцию как расширение, если они того пожелают.
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html
точность Указывает минимальное количество цифр, которое должно отображаться для спецификаторов преобразования d, o, i, u, x или X (поле заполняется начальными нулями), количество цифр, которое должно появляться после радикального символа для e и f. спецификаторы преобразования, максимальное количество значащих цифр для данного спецификатора преобразования; или максимальное количество байтов, которое будет записано из строки в спецификаторе преобразования s. Точность должна принимать форму ( '.'), За которым следует строка десятичного разряда; строка с нулевой цифрой рассматривается как ноль.
http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap05.html
Я заметил одну досадную вещь, которая заключается в том, что точка относится к числу байтов, а не к символам, так что на самом деле ее можно использовать только со стандартным набором символов ASCII. Так должно работать с тире (я имею ввиду -
). Там, видимо, ошибка в dash
Страница man, в которой упоминаются символы, но это должны быть байты.