引数として渡された Unicode 文字を printf を使用してデコードしようとしています

引数として渡された Unicode 文字を printf を使用してデコードしようとしています

私はこのようにパイプしたいくつかの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- 組み込みでは問題ないのに、printfexe では問題になるのは、 だけで%、 では問題になるのはなぜでしょうか$?

答え1

二重展開の問題 (\uが の前に処理される) を回避するには、少なくとも Bash では を%s使用できます。%bprintf

printf '%b\n' \\u0024 \\u0025

入力をさまざまな方法で前処理できます。

set 0024 0025
printf '%b\n' "${@/#/\\u}"

スタンドアロンprintfGNU coreutilsで実装されているでは、Unicode 文字仕様に次のような制限があります。

printfISO 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フォーマット文字列に文字通りを含める必要があります。

関連情報