
Estou tentando imprimir alguns códigos Unicode que insiro assim
echo 0024 0025 | xargs -n1 echo # one code per line
| xargs printf '\u%s\n'
esperando conseguir isso
$
%
mas é isso que eu recebo
printf: missing hexadecimal number in escape
Depois de algumas tentativas e erros, na verdade tenho dois problemas menores, e um faz sentido e o outro parece um mistério completo.
Problema 1:
printf '\u%s\n' 0024 0025
me dá isso
-bash: printf: missing unicode digit for \u
\u0024
-bash: printf: missing unicode digit for \u
\u0025
Problema 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
(usando >
for $
para que você possa ver $
na saída)
Por alguma razão, alguns personagens funcionam com a versão exe, mas outros nem todos funcionam com o printf integrado.
então aqui está uma solução alternativa que funcionaria se não fosse pelo problema nº 2 (mas pode ser um pouco mais lento do que minha ideia original)
echo 0024 0025 | xargs -n1 echo # one item per line
| xargs -I {} printf '\u{}\n'
mas devido ao problema nº 2, meio que funciona:
$ echo 0024 0025 | xargs -n1 echo | xargs -I {} printf '\u{}\n'
$
printf: invalid universal character name \u0025
($ sai, mas% recebe erro)
Então acho que minhas perguntas são:
-Existe alguma maneira de fazer printf funcionar com o código numérico para que eu possa executar printf uma vez em vez de uma vez por argumento -I
?
-O que estou fazendo de errado que o printf
built-in não se importe, mas printf
o exe não goste, mas apenas para %
e não para $
?
Responder1
Para evitar o problema de expansão dupla ( \u
é processado antes %s
), você pode usar %b
, pelo menos no Bash printf
:
printf '%b\n' \\u0024 \\u0025
Você pode pré-processar sua entrada de várias maneiras:
set 0024 0025
printf '%b\n' "${@/#/\\u}"
O autônomo printf
,conforme implementado em GNU coreutils, tem as seguintes restrições nas especificações de caracteres Unicode:
printf
interpreta duas sintaxes de caracteres introduzidas na ISO C 99: '\u
' para caracteres Unicode de 16 bits (ISO/IEC 10646), especificados como quatro dígitos hexadecimaisahhe '\U
' para caracteres Unicode de 32 bits, especificados como oito dígitos hexadecimaisahhhhhhh.printf
gera os caracteres Unicode de acordo com aLC_CTYPE
localidade. Caracteres Unicode nos intervalos U+0000…U+009F, U+D800…U+DFFF não podem ser especificados por esta sintaxe, exceto U+0024 ($), U+0040 (@) e U+0060 (`) .
Isso explica por que você não pode produzir %
dessa maneira.
Responder2
O utilitário padrão printf
não suporta \uxxxx
sequências de escape, consulte:https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html
Assumir que isso poderia funcionar depende de extensões que podem estar presentes em algumas implementações (por exemplo, em um ksh
builtin), mas não se pode esperar que sejam suportadas em geral. Veja o printf
documento padrão.
Outro problema parece ser a sua suposição de que chamar
printf '\u%s\n' 123
resultaria no mesmo que chamar:
printf '\u123\n'
Isso não funciona, pois printf
analisa a string de formato elemento por elemento e não vê a string de formato esperada.
Portanto, mesmo se você estiver usando bash
para executar o script, você pode esperar que o \uxx
escape da barra invertida seja expandido se dois dígitos hexadecimais se seguirem e a sequência de escape aparecer literalmente na string de formato. Se você deseja expandir 4 dígitos hexadecimais, você precisa \Uxxxx
literalmente na string de formato.