Использование оболочки 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, в которой упоминаются символы, но это должны быть байты.

Другие вопросы по тегам