POSIX 需要 printf
的%-20s
计算这20来讲字节不是字符,即使是没有什么意义,因为printf
是打印文本,格式化(见讨论在奥斯汀集团(POSIX)和bash
邮件列表)。
POSIX shell和其他大多数POSIX shell 的printf
内置组件都可以bash
证明这一点。
zsh
忽略了这个愚蠢的要求(即使在sh
仿真中也是如此),因此printf
可以按您期望的那样工作。printf
内建的相同fish
(不是POSIX类的shell)。
ü
以UTF-8编码时,字符(U + 00FC)由两个字节(0xc3和0xbc)组成,这说明了差异。
$ printf %s 'Früchte und Gemüse' | wc -mcL
18 20 18
该字符串由18个字符组成,宽18列(-L
是GNU wc
扩展,用于报告输入中最宽行的显示宽度),但编码为20个字节。
在zsh
或中fish
,文本将正确对齐。
现在,有些字符的宽度为0(例如,组合字符,例如U + 0308,组合偏斜),或者像许多亚洲脚本中一样,是全角字符(更不用说控制字符,例如Tab),甚至zsh
不能对齐那些正确的。
例如,在zsh
:
$ printf '%3s|\n' u ü $'u\u308' $'\u1100'
u|
ü|
ü|
ᄀ|
在bash
:
$ printf '%3s|\n' u ü $'u\u308' $'\u1100'
u|
ü|
ü|
ᄀ|
ksh93
具有一种%Ls
格式规范,可以根据显示宽度来计算宽度。
$ printf '%3Ls|\n' u ü $'u\u308' $'\u1100'
u|
ü|
ü|
ᄀ|
如果文本包含TAB之类的控制字符,这仍然行不通(怎么可能?printf
必须知道制表位在输出设备中相距多远以及开始在哪个位置打印)。尽管确实考虑到所有控制字符的宽度均为,但它确实偶然地使用了退格字符(如在roff
输出中,X
(粗体X
)写为X\bX
)。ksh93
-1
作为其他选择,您可以尝试:
printf '%s\t|\n' u ü $'u\u308' $'\u1100' | expand -t3
这适用于某些expand
实现(虽然不是GNU的)。
在GNU系统中,你可以使用GNU awk
其printf
计数字符(不是字节,而不是显示宽度,所以仍然不能确定为0,宽度或2角字符,但确定为您的样品):
gawk 'BEGIN {for (i = 1; i < ARGC; i++) printf "%-3s|\n", ARGV[i]}
' u ü $'u\u308' $'\u1100'
如果输出到终端,则还可以使用光标定位转义序列。喜欢:
forward21=$(tput cuf 21)
printf '%s\r%s%s\n' \
"Früchte und Gemüse" "$forward21" "foo" \
"Milchprodukte" "$forward21" "bar" \
"12345678901234567890" "$forward21" "baz"