Bourne shell“ printf%s”的用法

 zoooooz 发布于 2023-01-19 11:05

我有一个简单的debug_print shell函数,可用于编写较大的shell脚本。通常,我尝试仅编写兼容Bourne的脚本,并避免使用Bash-isms。在这种情况下,我的debug_print函数的Bash版本可以正常工作,但是我无法终生弄清楚为什么我的Bourne兼容版本失败了。具体来说,我的问题是在printf中使用%s格式修饰符。

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

接下来,在“没有这些工作”注释下的几行注释行中,您可以看到我在试图找出问题时使用的各种测试/方差。这些行之后是有效的Bourne版本,最后是有效的Bash版本。

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

为了确定“伯恩兼容性”,我在系统上使用破折号作为/ bin / sh,这是Debian系统的典型特征。Dash是为了有效执行脚本而不是交互使用。根据该手册页,它努力实现严格的Bourne兼容性,因此我认为,如果我的脚本使用破折号,则它应该是Bourne合理的兼容对象,并且不包含bash行为。此外,我认识到此功能并不是调试打印的全部/全部,并且可能会有很多特殊情况和需要改进的地方。我欢迎所有建议,但是我对此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 Shell标准不支持。

    要减少字符串的长度,可以在格式字段中使用点和变量:

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

    - 编辑 -

    在POSIX.1-2008的此卷中未作任何规定,允许指定字段宽度和精度,*因为*可以使用shell变量替换直接在格式操作数中替换。实施者也可以选择提供此功能作为扩展。

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

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

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

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

    2023-01-19 11:07 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有