
私はこのようにパイプしたいくつかのUnicodeコードをprintfしようとしています
echo 0024 0025 | xargs -n1 echo # one code per line
| xargs printf '\u%s\n'
これを手に入れたい
$
%
しかし、これが私の得たもの
printf: missing hexadecimal number in escape
何度か試行錯誤した結果、実は 2 つの小さな問題が見つかりました。1 つはなんとなく納得できるのですが、もう 1 つはまったくの謎のようです。
問題1:
printf '\u%s\n' 0024 0025
これを私に与えてくれる
-bash: printf: missing unicode digit for \u
\u0024
-bash: printf: missing unicode digit for \u
\u0025
問題2:
> # use built-in for $
> printf '\u0024\n'
$
> # use exe for $
> which printf
/usr/bin/printf
> /usr/bin/printf '\u0024\n'
$
> # now use built-in for %
> printf '\u0025\n'
%
> # but look what happens when we use exe for % !!!!
> /usr/bin/printf '\u0025\n'
/usr/bin/printf: invalid universal character name \u0025
(出力で確認できるように>
for を使用します)$
$
何らかの理由で、一部の文字は exe バージョンで動作しますが、組み込みの printf ではすべて動作するにもかかわらず、一部の文字は動作しません。
そこで、問題 2 がなければ機能する回避策を紹介します (ただし、当初のアイデアよりもかなり遅くなる可能性があります)
echo 0024 0025 | xargs -n1 echo # one item per line
| xargs -I {} printf '\u{}\n'
しかし、問題 2 のため、半分しか機能しません。
$ echo 0024 0025 | xargs -n1 echo | xargs -I {} printf '\u{}\n'
$
printf: invalid universal character name \u0025
($ は表示されますが、% はエラーになります)
私の質問は次のようになります:
- printf を数値コードで動作させて、引数ごとに 1 回ではなく 1 回実行できるようにする方法はありますか-I
?
printf
- 組み込みでは問題ないのに、printf
exe では問題になるのは、 だけで%
、 では問題になるのはなぜでしょうか$
?
答え1
二重展開の問題 (\u
が の前に処理される) を回避するには、少なくとも Bash では を%s
使用できます。%b
printf
printf '%b\n' \\u0024 \\u0025
入力をさまざまな方法で前処理できます。
set 0024 0025
printf '%b\n' "${@/#/\\u}"
スタンドアロンprintf
、GNU coreutilsで実装されているでは、Unicode 文字仕様に次のような制限があります。
printf
ISO C 99で導入された2つの文字構文を解釈します: '\u
' は16ビットUnicode (ISO/IEC 10646)文字で、4つの16進数で指定されます。うーん、および '\U
' は 32 ビット Unicode 文字で、8 桁の 16 進数で指定します。ああああああ. はロケールprintf
に応じて Unicode 文字を出力しますLC_CTYPE
。U+0024 ($)、U+0040 (@)、および U+0060 (`) を除き、U+0000…U+009F、U+D800…U+DFFF の範囲の Unicode 文字はこの構文では指定できません。
%
これが、なぜこの方法で生産できないのかを説明しています。
答え2
標準printf
ユーティリティはエスケープ シーケンスをサポートしていません\uxxxx
。以下を参照してください。https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html
これが機能するかどうかは、いくつかの実装(たとえば組み込みksh
)に存在する可能性のある拡張機能に依存しますが、一般的にサポートされることは期待できません。標準ドキュメントを参照してくださいprintf
。
もう一つの問題は、電話をかけるというあなたの仮定にあるようです
printf '\u%s\n' 123
呼び出しと同じ結果になります:
printf '\u123\n'
これは機能しません。printf
フォーマット文字列を要素ごとに解析し、期待されるフォーマット文字列が検出されないからです。
したがって、スクリプトを実行するために を使用している場合でもbash
、2 つの 16 進数が続き、エスケープ シーケンスがフォーマット文字列に文字通り表示される場合は、バックスラッシュ エスケープが展開されることが予想さ\uxx
れます。4 つの 16 進数を展開したい場合は、\Uxxxx
フォーマット文字列に文字通りを含める必要があります。