POSIX ต้อง printf
ของ%-20s
การนับผู้ที่ 20 ในแง่ของไบต์ไม่ได้ตัวละครแม้ว่าที่ทำให้ความรู้สึกเล็ก ๆ น้อย ๆ เป็นprintf
คือการพิมพ์ข้อความในรูปแบบ (ดูการอภิปรายที่ออสตินกลุ่ม (POSIX) และbash
รายการทางไปรษณีย์)
printf
builtin ของbash
และส่วนใหญ่เปลือกหอย POSIX อื่น ๆ ที่ให้เกียรติ
zsh
ไม่สนใจข้อกำหนดโง่ ๆ (แม้จะเป็นsh
อีมูเลชัน) ดังนั้นprintf
ทำงานได้ตามที่คุณคาดหวัง เหมือนกันสำหรับบิวด์อินprintf
ของfish
(ไม่ใช่เชลล์เหมือน POSIX)
ü
ตัวอักษร (U + 00FC) เมื่อการเข้ารหัสใน UTF-8 ทำสองไบต์ (0xc3 และ 0xbc) ซึ่งอธิบายถึงความแตกต่าง
$ printf %s 'Früchte und Gemüse' | wc -mcL
18 20 18
สตริงนั้นทำจาก 18 อักขระกว้าง 18 คอลัมน์ ( -L
เป็นwc
ส่วนขยายของGNU เพื่อรายงานความกว้างในการแสดงผลของบรรทัดที่กว้างที่สุดในอินพุต) แต่ถูกเข้ารหัสบน 20 ไบต์
ในzsh
หรือfish
ข้อความจะถูกจัดตำแหน่งอย่างถูกต้อง
ตอนนี้ยังมีอักขระที่มีความกว้าง 0 (เช่นการรวมอักขระเช่น U + 0308, diaresis รวม) หรือมีความกว้างสองเท่าเช่นในสคริปต์ Asiatic จำนวนมาก (ไม่พูดถึงอักขระควบคุมเช่น 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
จะต้องทราบว่าแท็บหยุดห่างกันมากแค่ไหนในอุปกรณ์แสดงผลและตำแหน่งที่เริ่มพิมพ์) มันไม่ทำงานโดยอุบัติเหตุกับตัวละคร Backspace (เช่นเดียวกับใน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"