intentando usar printf para decodificar caracteres Unicode pasados ​​como argumentos

intentando usar printf para decodificar caracteres Unicode pasados ​​como argumentos

Estoy intentando imprimir algunos códigos Unicode que canalizo de esta manera

echo 0024 0025 | xargs -n1 echo # one code per line
  | xargs printf '\u%s\n'

esperando conseguir esto

$
%

pero esto es lo que obtengo

printf: missing hexadecimal number in escape

Después de algunas pruebas y errores, en realidad tengo dos problemas más pequeños, uno tiene sentido y el otro parece un completo misterio.


Problema 1:

printf '\u%s\n' 0024 0025

me da esto

-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 pueda ver el $resultado)

Por alguna razón, algunos caracteres funcionan con la versión exe, pero otros no, aunque todos funcionan con printf incorporado.


Así que aquí hay una solución que funcionaría si no fuera por el problema n.° 2 (pero podría ser un poco más lento que mi idea original).

echo 0024 0025 | xargs -n1 echo # one item per line
  | xargs -I {} printf '\u{}\n'

pero debido al problema número 2, funciona a medias:

$ echo 0024 0025 | xargs -n1 echo | xargs -I {} printf '\u{}\n'
$
printf: invalid universal character name \u0025

($ sale pero % obtiene error)


Entonces supongo que mis preguntas son:

-¿Hay alguna forma de hacer que printf funcione con el código numérico para poder ejecutar printf una vez en lugar de una vez por argumento -I?

-¿Qué estoy haciendo mal que al printfsistema integrado no le importa, pero printfal exe no le gusta, pero solo para %y no para $?

Respuesta1

Para evitar el problema de la doble expansión ( \use procesa antes %s), puedes usar %b, al menos en Bash printf:

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

Puede preprocesar su entrada de varias maneras:

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

El independiente printf,tal como se implementa en GNU coreutils, tiene las siguientes restricciones en las especificaciones de caracteres Unicode:

printfinterpreta dos sintaxis de caracteres introducidas en ISO C 99: ' \u' para caracteres Unicode de 16 bits (ISO/IEC 10646), especificados como cuatro dígitos hexadecimaleshhhhy ' \U' para caracteres Unicode de 32 bits, especificados como ocho dígitos hexadecimaleshhhhhhhh. printfgenera los caracteres Unicode según la LC_CTYPEconfiguración regional. Esta sintaxis no puede especificar caracteres Unicode en los rangos U+0000…U+009F, U+D800…U+DFFF, excepto U+0024 ($), U+0040 (@) y U+0060 (`). .

Esto explica por qué no se puede producir %de esta manera.

Respuesta2

La utilidad estándar printfno admite \uxxxxsecuencias de escape, consulte:https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html

Asumir que esto podría funcionar depende de extensiones que podrían estar presentes en algunas implementaciones (por ejemplo, en una kshfunción incorporada), pero no se puede esperar que sean compatibles en general. Ver el printfdocumento estándar.

Otro problema parece ser su suposición de que llamar

printf '\u%s\n' 123

resultaría en lo mismo que llamar:

printf '\u123\n'

Esto no funciona, ya que printfanaliza la cadena de formato elemento por elemento y no ve la cadena de formato esperada.

Entonces, incluso si está utilizando bashpara ejecutar el script, puede esperar que la \uxxbarra invertida se expanda si siguen dos dígitos hexadecimales y la secuencia de escape aparece literalmente en la cadena de formato. Si desea tener 4 dígitos hexadecimales expandidos, debe tenerlos \Uxxxxliteralmente en la cadena de formato.

información relacionada