POSIX đòi hỏi printf
's %-20s
để đếm những 20 về byte không nhân vật mặc dù tạo ra rất ít cảm giác như printf
là in văn bản , định dạng (xem thảo luận tại Tập đoàn Austin (POSIX) và bash
mailing list).
Việc xây printf
dựng bash
và hầu hết các vỏ POSIX khác tôn vinh điều đó.
zsh
bỏ qua yêu cầu ngớ ngẩn đó (ngay cả trong sh
thi đua) để printf
hoạt động như bạn mong đợi ở đó. Tương tự đối với phần printf
dựng sẵn của fish
(không phải là vỏ giống POSIX).
Ký ü
tự (U + 00FC), khi được mã hóa bằng UTF-8 được tạo thành từ hai byte (0xc3 và 0xbc), giải thích sự khác biệt.
$ printf %s 'Früchte und Gemüse' | wc -mcL
18 20 18
Chuỗi đó được tạo thành từ 18 ký tự, rộng 18 cột ( -L
là wc
phần mở rộng GNU để báo cáo độ rộng hiển thị của dòng rộng nhất trong đầu vào) nhưng được mã hóa trên 20 byte.
Trong zsh
hoặc fish
, văn bản sẽ được căn chỉnh chính xác.
Giờ đây, cũng có những ký tự có độ rộng 0 (như kết hợp các ký tự như U + 0308, diaresis kết hợp) hoặc có độ rộng gấp đôi như trong nhiều tập lệnh Asiatic (không đề cập đến các ký tự điều khiển như Tab) và thậm chí zsh
sẽ không căn chỉnh những cái đó đúng
Ví dụ, trong zsh
:
$ printf '%3s|\n' u ü $'u\u308' $'\u1100'
u|
ü|
ü|
ᄀ|
Trong bash
:
$ printf '%3s|\n' u ü $'u\u308' $'\u1100'
u|
ü|
ü|
ᄀ|
ksh93
có một %Ls
đặc điểm kỹ thuật định dạng để đếm chiều rộng theo chiều rộng màn hình .
$ printf '%3Ls|\n' u ü $'u\u308' $'\u1100'
u|
ü|
ü|
ᄀ|
Điều đó vẫn không hoạt động nếu văn bản chứa các ký tự điều khiển như TAB (làm thế nào nó printf
có thể phải biết các điểm dừng cách xa nhau trong thiết bị đầu ra và vị trí bắt đầu in ở vị trí nào). Nó hoạt động một cách tình cờ với các ký tự backspace (như trong roff
đầu ra trong đó X
(in đậm X
) được viết là X\bX
) mặc dù ksh93
coi tất cả các ký tự điều khiển là có chiều rộng -1
.
Như các tùy chọn khác, bạn có thể thử:
printf '%s\t|\n' u ü $'u\u308' $'\u1100' | expand -t3
Điều đó hoạt động với một số expand
triển khai (mặc dù không phải GNU).
Trên các hệ thống GNU, bạn có thể sử dụng GNU awk
có printf
số đếm bằng ký tự (không phải byte, không phải chiều rộng hiển thị, do đó vẫn không ổn đối với các ký tự 0 chiều rộng hoặc 2 chiều rộng, nhưng OK cho mẫu của bạn):
gawk 'BEGIN {for (i = 1; i < ARGC; i++) printf "%-3s|\n", ARGV[i]}
' u ü $'u\u308' $'\u1100'
Nếu đầu ra đi đến một thiết bị đầu cuối, bạn cũng có thể sử dụng các chuỗi thoát định vị con trỏ. Như:
forward21=$(tput cuf 21)
printf '%s\r%s%s\n' \
"Früchte und Gemüse" "$forward21" "foo" \
"Milchprodukte" "$forward21" "bar" \
"12345678901234567890" "$forward21" "baz"