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