
Я пытаюсь вывести на печать некоторые коды Unicode, которые я передаю следующим образом
echo 0024 0025 | xargs -n1 echo # one code per line
| xargs printf '\u%s\n'
надеясь получить это
$
%
но вот что я получаю
printf: missing hexadecimal number in escape
После нескольких проб и ошибок у меня на самом деле возникло две небольшие проблемы, одна из которых имеет смысл, а другая кажется полной загадкой.
Проблема 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 работать с числовым кодом, чтобы я мог запустить printf один раз, а не один раз для каждого аргумента с помощью -I
?
-Что я делаю не так, что printf
встроенный не против, а printf
exe не любит, но только для %
, а не для $
?
решение1
Чтобы избежать проблемы двойного расширения ( \u
обрабатывается раньше %s
), можно использовать %b
, по крайней мере в Bash printf
:
printf '%b\n' \\u0024 \\u0025
Вы можете предварительно обработать свои входные данные различными способами:
set 0024 0025
printf '%b\n' "${@/#/\\u}"
Автономный printf
,как реализовано в GNU coreutils, имеет следующие ограничения на спецификации символов Unicode:
printf
интерпретирует два синтаксиса символов, представленных в ISO C 99: '\u
' для 16-битных символов Unicode (ISO/IEC 10646), указанных как четыре шестнадцатеричные цифрыхххх, и '\U
' для 32-битных символов Unicode, указанных как восемь шестнадцатеричных цифрххххххх.printf
выводит символы Unicode в соответствии сLC_CTYPE
локалью. Символы Unicode в диапазонах U+0000…U+009F, U+D800…U+DFFF не могут быть указаны этим синтаксисом, за исключением U+0024 ($), U+0040 (@) и U+0060 (`).
Это объясняет, почему нельзя производить продукцию %
таким образом.
решение2
Стандартная printf
утилита не поддерживает \uxxxx
escape-последовательности, см.:https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html
Предположение, что это может работать, зависит от расширений, которые могут присутствовать в нескольких реализациях (например, во ksh
встроенной), но нельзя ожидать, что они будут поддерживаться в целом. См. printf
стандартный документ.
Другая проблема, по-видимому, заключается в вашем предположении, что звонок
printf '\u%s\n' 123
приведет к тому же результату, что и вызов:
printf '\u123\n'
Это не работает, так как printf
анализирует строку формата поэлементно и не видит ожидаемую строку формата.
Так что даже если вы используете bash
для выполнения скрипта, вы можете просто ожидать, что \uxx
экранирование обратной косой черты будет расширено, если последуют две шестнадцатеричные цифры, а последовательность экранирования появится буквально в строке формата. Если вы хотите, чтобы 4 шестнадцатеричные цифры были расширены, вам нужно иметь \Uxxxx
буквально в строке формата.