POSIX membutuhkan printf 's %-20suntuk menghitung orang-orang 20 dalam hal byte tidak karakter meskipun itu masuk akal sebagai printfadalah untuk mencetak teks , diformat (lihat diskusi di Austin Grup (POSIX) dan bashmailing list).
Kerangka printfbawaan bashdan sebagian besar kerang POSIX lainnya menghormatinya.
zshmengabaikan persyaratan konyol (bahkan dalam shpersaingan) sehingga printfberfungsi seperti yang Anda harapkan di sana. Sama untuk printfbuiltin 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 ( -Lmenjadi wcekstensi GNU untuk melaporkan lebar tampilan garis terluas dalam input) tetapi dikodekan pada 20 byte.
Di zshatau 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 zshtidak 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|
ü|
ü|
ᄀ|
ksh93memiliki %Lsspesifikasi 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? printfHarus 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 roffoutput di mana X(dicetak tebal X) ditulis X\bX) meskipun ksh93menganggap 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 expandimplementasi (bukan GNU sekalipun).
Pada sistem GNU, Anda bisa menggunakan GNU awkyang printfmenghitung 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"