
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 printf
sistema integrado no le importa, pero printf
al exe no le gusta, pero solo para %
y no para $
?
Respuesta1
Para evitar el problema de la doble expansión ( \u
se 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:
printf
interpreta 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.printf
genera los caracteres Unicode según laLC_CTYPE
configuració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 printf
no admite \uxxxx
secuencias 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 ksh
función incorporada), pero no se puede esperar que sean compatibles en general. Ver el printf
documento 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 printf
analiza la cadena de formato elemento por elemento y no ve la cadena de formato esperada.
Entonces, incluso si está utilizando bash
para ejecutar el script, puede esperar que la \uxx
barra 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 \Uxxxx
literalmente en la cadena de formato.