A razão do erro que você tem é que:
O printf embutido entende o \U
(ou \u
) somente quando é seguido por um número real:
$ printf '\U0021'
!
Para criar o número e também convertê-lo, um printf de dois passos é necessário (um double \ é necessário para passar pelas aspas duplas):
$ printf '%b' "$(printf '\U%04X' 33)"
!
Como você quer:
$ printf '%b' "$(printf '\u%0*X' 4 33)"
!
Isso também funciona:
$ printf '%b' "$(printf '\U%0*X' 8 33)"
!
Não há necessidade de usar bc para contar a quantidade de números hexadecimais.
bash poderia entender isso perfeitamente:
$ a=$(( 0xdef )); echo $(( a + 1 ))
3568
E para obter o valor hexadecimal de um número printf
é bom o suficiente:
$ printf '0x%06x' 3568
0x000df0
O loop pode ser simplificado para:
#!/bin/bash
cp=$((0x020)) len=6
for (( cp=32; cp<$((0x010000)); cp++)); do
Ucode="$(printf '%b' "$(printf '\U%0*X' "$len" "$cp")")"
printf 'Unicode U%0*x = %s\n' 4 "$cp" "$Ucode"
done
BEWARE De 0x20 a 0x010000, há muitas linhas (~ 64k linhas).
Eu aumentei o len para 6, já que o UNICODE poderia ter pontos de código de até 10FFFF.
Claro, o Ucode é totalmente definido por isso:
Ucode="$(printf '%b' "$(printf '\U%0*X' $len "$cp")")"
Observe que os pontos de código ( cp
) abaixo de dec = 32 ou HEX = 0x20 são caracteres de controle.
Mesmo que o código funcione para esses pontos de código, eu não recomendo que você toque com eles.
EXCETO para UNICODE U0000 porque o valor está sendo atribuído a uma variável.
Isto imprime %code%
$ printf '%b' "$(printf '\U%0*X' "6" "0")"
Confirme com xxd:
$ printf '%b' "$(printf '\U%0*X' "6" "0")" | xxd
0000000: 00
CAVEAT : O Bash abaixo de 4.3 não codifica corretamente os valores entre U0080 e U00FF em utf-8. Por favor use a versão 4.3 ou 4.4.