バイト文字列の長さの代わりに '%10s' printf形式の文字列長を計算するようにawkに指示できますか?

バイト文字列の長さの代わりに '%10s' printf形式の文字列長を計算するようにawkに指示できますか?

次の出力を試してください|Ü| X|

echo 'Ü X' | awk '{printf("|% 2s|% 2s|\n", $1, $2)}'

明らかにawk文字長ではなくバイト長が計算されるため、Ü数は2で、左マージンは必要ありませんX

awk重要なモードで実行できますか?特徴バイト長ではなくパターン長%<count>s printfですか?

これ同じbash問題がありますprintf。答えが違うことを願っています。 「libc printfへのパス」:-/

私は〜だったいいえgawkバージョンに関係なく使用Ubuntu22.04(Jammy Jellyfish)がすでにインストールしています。gawk最近はインストールできないと思いました:-/

答え1

GNU awk(他のawkバリエーションがあるかもしれません):

$ echo 'Ü X' | LC_ALL='en_US.UTF-8' awk '{printf "|% 2s|% 2s|\n", $1, $2}'
| Ü| X|

バッシュ 3.0+(調整する必要がある他のシェルがあるかもしれません):

$ LC_ALL='en_US.UTF-8' a='Ü' b='X'
$ printf '|%*s%s|%*s%s|\n' "$(( 2 - ${#a} ))" '' "$a" "$(( 2 - ${#b} ))" '' "$b"
| Ü| X|

bashのバージョンは、バージョンが発生する環境だけでなくLC_ALL実行中のシェルでも設定する必要があるため、呼び出しシェルでそれを変更したくない場合は、保存/復元する必要があります。つまり、またはサブシェルですべての操作を実行します。つまり、 。${#a}printfawkLC_ALLo="$LC_ALL"; LC_ALL='en_US.UTF-8' ... "$b"; LC_ALL="$o"( LC_ALL='en_US.UTF-8' ... "$b" )

説明する:

~からGNU awkドキュメント:

-b
--characters-as-bytes

gawkがすべての入力データを単一バイト文字として扱うようにします。また、print または printf を使用して作成されたすべての出力は、シングルバイト文字として扱われます。

通常、gawkはPOSIX標準に準拠し、現在のロケールに従って入力データを処理しようとします(参照:あなたの場所はさまざまです)。これには通常、マルチバイト文字をワイド文字に(内部的に)変換することが含まれ、入力データに有効なマルチバイト文字が含まれていないと問題や混乱が発生する可能性があります。このオプションは、gawkに「私のデータを削除してください!」と通知する簡単な方法です。

適切なロケールセットでGNU awk 5.2.2を使用すると、マルチバイト文字を単一のマルチバイト文字として扱います。

$ echo 'Ü X' | LC_ALL='en_US.UTF-8' awk '{printf "|% 2s|% 2s|\n", $1, $2}'
| Ü| X|

他のロケールを使用または使用している間、-bすべての入力は単一バイト文字として扱われます。

$ echo 'Ü X' | LC_ALL='C' awk '{printf "|% 2s|% 2s|\n", $1, $2}'
|Ü| X|

$ echo 'Ü X' | awk -b '{printf "|% 2s|% 2s|\n", $1, $2}'
|Ü| X|

使用時の-b結果はロケールとは無関係です。

$ echo 'Ü X' | LC_ALL='en_US.UTF-8' awk -b '{printf "|% 2s|% 2s|\n", $1, $2}'
|Ü| X|

$ echo 'Ü X' | LC_ALL='C' awk -b '{printf "|% 2s|% 2s|\n", $1, $2}'
|Ü| X|

〜のように@StéphaneChazelasで言及コメント、望むよりprintfが分音符を「縮小」するのはなぜですか?printfシェルの関連動作の場合@Léa Grisの返信bash 3.0以降でフォーマットされた出力が正しくなるように文字数を取得することをお勧めします。

$ a='Ü' b='X' LC_ALL='en_US.UTF-8' 
$ printf '|%*s%s|%*s%s|\n' "$(( 2 - ${#a} ))" '' "$a" "$(( 2 - ${#b} ))" '' "$b"
| Ü| X|

この機能はロケール設定の影響も受けます。

$ LC_ALL='C'
$ printf "|%*s%s|%*s%s|\n" "$(( 2 - ${#a} ))" '' "$a" "$(( 2 - ${#b} ))" '' "$b"
|Ü| X|

また、見ることができますBashの文字列長Bashから文字の長さを取得する方法に関する追加情報。

関連情報