我有一个简单的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..."
谢谢你的帮助。
您是为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
手册页中显然有一个提到字符的错误,但是应该是字节。