Bourne shell“printf%s”用法

时间:2014-03-09 05:10:36

标签: bash shell printf sh dash-shell

我有一个简单的debug_print shell函数,用于帮助编写更大的shell脚本。一般来说,我尝试只编写与Bourne兼容的脚本并避免使用Bash-isms。在这种情况下,我的debug_print函数的Bash版本工作正常,但我不能为我的生活弄清楚为什么我的Bourne兼容版本失败。具体来说,我的问题是使用%s格式修饰符和printf。

我在下面提供了我的测试脚本。 debug_print函数显示带有标签的标题栏,其字符串或文件参数的内容,最后显示与标题宽度相同的页脚栏。问题在于显示页脚栏并以注释“显示页脚线...”开头。之后的两条未注释的行是我认为应该工作的,但不是。

接下来是“没有这些工作”评论下的几条注释行,你可以看到我在尝试找出问题时使用的各种测试/差异。在那些行之后是一个有效的Bourne版本,最后是一个有效的Bash版本。

我已经阅读了痛苦细节的联机帮助页,并尝试了各种各样的格式字符串,引用和我可以想到的变量用法。到目前为止,这些尝试都没有奏效。在“没有这些工作”注释下,无工作命令都打印出整个字符串,而不是我认为应该只显示字段宽度修饰符指定的字符数。

要确定“Bourne兼容性”,我在我的系统上使用dash作为/ bin / sh,这是Debian系统的典型。 Dash用于高效的脚本执行而非交互式使用。根据该联机帮助页,它努力实现严格的Bourne兼容性,因此我有理由认为如果我的脚本使用破折号,那么它应该是合理的Bourne兼容并且没有bash-isms。此外,我认识到这个功能不是调试打印的全部/全部,并且可能存在许多极端情况和可以改进的区域。我欢迎所有的建议,但我对这个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 个答案:

答案 0 :(得分:5)

你是在为POSIX合规性还是Bourne-shell合规性写作,那些是不同的东西.. dash努力实现严格的POSIX合规性,而不是Bourne合规性。

此外,可变字段宽度:

printf "%*s\n" "$header_len" "$dashes"
POSIX shell标准不支持

要剪切字符串长度,您可以在格式字段中使用点和变量:

printf "%.${header_len}s\n" "$dashes"

- 编辑 -

  

本卷POSIX.1-2008中没有规定允许字段   宽度和精度要指定为*,因为*可以   使用shell变量直接在格式操作数中替换   代换。实现也可以提供此功能   如果他们愿意,可以延期。

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html#tag_20_94_16

  

精度        给出d,o的最小位数,        i,u,x或X转换说明符(该字段用前导填充        零(),基数字符后出现的位数        e和f转换说明符,最大有效数        g转换说明符的数字;或最大字节数        从s转换说明符中的字符串写入。该        精度应采用('。')后跟a的形式        十进制数字串;空数字字符串被视为零。

http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap05.html#tag_05

我确实注意到一件令人讨厌的事情,那就是点与字节数有关,而不是字符,所以它实际上只能用于标准的ASCII字符集。所以它应该与破折号一起使用(我的意思是-)。显然在dash手册页中有一个提到字符的错误,但应该是字节。