POSIX membutuhkan printf
's %-20s
untuk menghitung orang-orang 20 dalam hal byte tidak karakter meskipun itu masuk akal sebagai printf
adalah untuk mencetak teks , diformat (lihat diskusi di Austin Grup (POSIX) dan bash
mailing list).
Kerangka printf
bawaan bash
dan sebagian besar kerang POSIX lainnya menghormatinya.
zsh
mengabaikan persyaratan konyol (bahkan dalam sh
persaingan) sehingga printf
berfungsi seperti yang Anda harapkan di sana. Sama untuk printf
builtin dari fish
(bukan shell seperti POSIX).
The ü
karakter (U + 00FC), ketika dikodekan dalam UTF-8 terbuat dari dua byte (0xc3 dan 0xbc), yang menjelaskan perbedaan tersebut.
$ printf %s 'Früchte und Gemüse' | wc -mcL
18 20 18
String itu terdiri dari 18 karakter, lebar 18 kolom ( -L
menjadi wc
ekstensi GNU untuk melaporkan lebar tampilan garis terluas dalam input) tetapi dikodekan pada 20 byte.
Di zsh
atau fish
, teks akan disejajarkan dengan benar.
Sekarang, ada juga karakter yang memiliki 0-lebar (seperti menggabungkan karakter seperti U + 0308, yang menggabungkan diaresis) atau memiliki lebar ganda seperti di banyak skrip Asiatik (belum lagi karakter kontrol seperti Tab) dan bahkan zsh
tidak akan menyelaraskan mereka dengan benar.
Contoh, di zsh
:
$ printf '%3s|\n' u ü $'u\u308' $'\u1100'
u|
ü|
ü|
ᄀ|
Dalam bash
:
$ printf '%3s|\n' u ü $'u\u308' $'\u1100'
u|
ü|
ü|
ᄀ|
ksh93
memiliki %Ls
spesifikasi format untuk menghitung lebar dalam hal tampilan lebar.
$ printf '%3Ls|\n' u ü $'u\u308' $'\u1100'
u|
ü|
ü|
ᄀ|
Itu masih tidak berfungsi jika teks berisi karakter kontrol seperti TAB (bagaimana mungkin? printf
Harus tahu seberapa jauh jarak tab berhenti di perangkat output dan di mana ia mulai mencetak). Ia bekerja secara tidak sengaja dengan karakter backspace (seperti dalam roff
output di mana X
(dicetak tebal X
) ditulis X\bX
) meskipun ksh93
menganggap semua karakter kontrol memiliki lebar -1
.
Sebagai opsi lain, Anda dapat mencoba:
printf '%s\t|\n' u ü $'u\u308' $'\u1100' | expand -t3
Itu bekerja dengan beberapa expand
implementasi (bukan GNU sekalipun).
Pada sistem GNU, Anda bisa menggunakan GNU awk
yang printf
menghitung dalam karakter (bukan byte, bukan lebar layar, jadi masih tidak OK untuk karakter 0 lebar atau 2 lebar, tapi OK untuk sampel Anda):
gawk 'BEGIN {for (i = 1; i < ARGC; i++) printf "%-3s|\n", ARGV[i]}
' u ü $'u\u308' $'\u1100'
Jika output masuk ke terminal, Anda juga dapat menggunakan urutan pelarian posisi kursor. Suka:
forward21=$(tput cuf 21)
printf '%s\r%s%s\n' \
"Früchte und Gemüse" "$forward21" "foo" \
"Milchprodukte" "$forward21" "bar" \
"12345678901234567890" "$forward21" "baz"