POSIX verlangt printf , dass %-20sdiese 20 in Bytes und nicht in Zeichen gezählt werden , obwohl dies wenig sinnvoll printfist, da Text formatiert gedruckt wird (siehe Diskussion bei der Austin Group (POSIX) und bashMailinglisten).
Die printfeingebauten bashund die meisten anderen POSIX-Shells berücksichtigen dies .
zshIgnoriert diese dumme Anforderung (auch in der shEmulation), printffunktioniert also so, wie Sie es dort erwarten würden. Gleiches gilt für das printfBuiltin von fish(keine POSIX-ähnliche Shell).
Das üin UTF-8 codierte Zeichen (U + 00FC) besteht aus zwei Bytes (0xc3 und 0xbc), was die Diskrepanz erklärt.
$ printf %s 'Früchte und Gemüse' | wc -mcL
18 20 18
Diese Zeichenfolge besteht aus 18 Zeichen, ist 18 Spalten breit ( -Leine GNU- wcErweiterung, die die Anzeigebreite der breitesten Zeile in der Eingabe angibt), ist jedoch in 20 Bytes codiert.
In zshoder fishwürde der Text korrekt ausgerichtet.
Es gibt jetzt auch Zeichen mit der Breite 0 (wie das Kombinieren von Zeichen wie U + 0308, das Kombinieren von Diaresis) oder mit der doppelten Breite wie in vielen asiatischen Skripten (ganz zu schweigen von Steuerzeichen wie Tabulator) und die sogar zshnicht ausgerichtet werden würden die richtig.
Beispiel in zsh:
$ printf '%3s|\n' u ü $'u\u308' $'\u1100'
u|
ü|
ü|
ᄀ|
In bash:
$ printf '%3s|\n' u ü $'u\u308' $'\u1100'
u|
ü|
ü|
ᄀ|
ksh93hat eine %LsFormatspezifikation zum Zählen der Breite in Bezug auf die Anzeigebreite .
$ printf '%3Ls|\n' u ü $'u\u308' $'\u1100'
u|
ü|
ü|
ᄀ|
Das funktioniert immer noch nicht, wenn der Text Steuerzeichen wie TAB enthält (wie könnte es sein, printfmüsste wissen, wie weit die Tabstopps im Ausgabegerät voneinander entfernt sind und an welcher Position der Druck beginnt). Es funktioniert aus Versehen mit Backspace-Zeichen (wie in der roffAusgabe, in der X(fett X) geschrieben ist als X\bX), obwohl ksh93alle Steuerzeichen eine Breite von haben -1.
Als weitere Optionen könnten Sie versuchen:
printf '%s\t|\n' u ü $'u\u308' $'\u1100' | expand -t3
Das funktioniert bei einigen expandImplementierungen (allerdings nicht bei GNUs).
Auf GNU-Systemen könnten Sie GNU verwenden, awkdessen printfAnzahl in Zeichen angegeben ist (keine Bytes, keine Anzeigebreiten, also immer noch nicht OK für die Zeichen mit 0 oder 2 Breiten, aber OK für Ihr Beispiel):
gawk 'BEGIN {for (i = 1; i < ARGC; i++) printf "%-3s|\n", ARGV[i]}
' u ü $'u\u308' $'\u1100'
Wenn die Ausgabe an ein Terminal gesendet wird, können Sie auch Escape-Sequenzen für die Cursorpositionierung verwenden. Mögen:
forward21=$(tput cuf 21)
printf '%s\r%s%s\n' \
"Früchte und Gemüse" "$forward21" "foo" \
"Milchprodukte" "$forward21" "bar" \
"12345678901234567890" "$forward21" "baz"