次の簡単なスクリプトを実行すると、
#!/bin/bash
printf "%-20s %s\n" "Früchte und Gemüse" "foo"
printf "%-20s %s\n" "Milchprodukte" "bar"
printf "%-20s %s\n" "12345678901234567890" "baz"
それは印刷します:
Früchte und Gemüse foo
Milchprodukte bar
12345678901234567890 baz
つまり、ウムラウト付きのテキスト(ü
など)は、ウムラウトごとに1文字ずつ「縮小」されます。
確かに、どこかに間違った設定がありますが、どれが正しい設定なのかわかりません。
これは、ファイルのエンコーディングがUTF-8の場合に発生します。
エンコーディングをlatin-1に変更すると、配置は正しくなりますが、ウムラウトが正しくレンダリングされません。
Fr�chte und Gem�se foo
Milchprodukte bar
12345678901234567890 baz
POSIXrequiresprintf
's %-20s
to count the 20 of the 20 ofbytes notcharactersprintf
はtextを出力するので意味がありませんが、フォーマットされています(ディスカッション Austin Groupで)を参照してください (POSIX)および bash
メーリングリスト)。
printf
のbash
ビルトインと他のほとんどのPOSIXシェルはこれを尊重します。
zsh
はその愚かな要件を無視するため(sh
エミュレーションでも)、printf
は期待どおりに機能します。 printf
のfish
ビルトイン(POSIXのようなシェルではない)でも同じです。
ü
文字(U + 00FC)は、UTF-8でエンコードされている場合、2バイト(0xc3および0xbc)で構成されており、矛盾を説明しています。
$ printf %s 'Früchte und Gemüse' | wc -mcL
18 20 18
その文字列は18文字で構成され、幅は18列です(-L
はGNU wc
拡張であり、入力の最も広い行の表示幅を報告します)。ただし、20バイトでエンコードされます。
zsh
またはfish
では、テキストは正しく配置されます。
現在、幅が0の文字(U + 0308のような結合文字など)や、多くのアジア言語のスクリプトのように2倍幅の文字(タブのような制御文字は言うまでもありません)もあり、zsh
も使用できませんそれらを適切に揃えます。
例、zsh
の場合:
$ printf '%3s|\n' u ü $'u\u308' $'\u1100'
u|
ü|
ü|
ᄀ|
bash
内:
$ printf '%3s|\n' u ü $'u\u308' $'\u1100'
u|
ü|
ü|
ᄀ|
ksh93
には、display幅で幅をカウントする%Ls
フォーマット指定があります。
$ printf '%3Ls|\n' u ü $'u\u308' $'\u1100'
u|
ü|
ü|
ᄀ|
それでもは機能しませんテキストにTABなどの制御文字が含まれている場合(---どうすればよいですか?printf
は、出力デバイスのタブストップの距離と位置を知っている必要があります。で印刷を開始します)。バックスペース文字(roff
の出力(X
(bold X
)is X\bX
)と記述されている)は偶然に機能しますが、ksh93
はすべての制御文字と見なされます-1
の幅を持つものとして。
他のオプションとして、あなたは試すことができます:
printf '%s\t|\n' u ü $'u\u308' $'\u1100' | expand -t3
これは一部のexpand
実装(GNUではありません)で機能します。
GNUシステムでは、GNU awk
が文字数でカウントされるprintf
を使用できます(バイトではなく、表示幅ではないため、0幅では問題があります。または全角文字ですが、サンプルには問題ありません):
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"
エンコーディングをlatin-1に変更すると、配置は正しくなりますが、ウムラウトが正しくレンダリングされません。
Fr�chte und Gem�se foo Milchprodukte bar 12345678901234567890 baz
実際には、いいえ、しかしあなたの端末はラテン-1を話さないので、ウムラウトではなくジャンクを取得します。
これを修正するには、iconvを使用します。
printf foo bar | iconv -f ISO8859-1 -t UTF-8
(または単にiconvにパイプされたシェルスクリプト全体を実行します)