Converte uma lista de valores decimais em um arquivo de texto em formato hexadecimal

2

Eu preciso converter uma lista de valores decimais em um arquivo de texto em formato hexadecimal, portanto, por exemplo, o arquivo test.txt pode conter:

131072
196608
262144
327680
393216
...

a saída deve ser uma lista de valores hexadecimais (hex 8 dígitos, com zeros à esquerda):

00020000
00030000
00040000
...

a saída é impressa no arquivo de texto. Como fazer isso com script de shell python ou linux?

EDIT # 1

Eu perdi uma operação extra: Eu preciso adicionar 80000000 hex a cada um dos valores hexadecimais criados. (adição aritmética, para aplicar a lista já criada de valores hexadecimais).

    
por minto 21.07.2018 / 15:29

6 respostas

10

Você pode fazer isso usando printf e bash :

printf '%08x\n' $(< test.txt)

Ou usando printf e bc ... apenas ... porque?

printf '%08s\n' $(bc <<<"obase=16; $(< test.txt)")

Para imprimir a saída em um arquivo de texto, use apenas o redirecionamento de shell > like:

printf '%08x\n' $(< test.txt) > output.txt
    
por 21.07.2018 / 15:39
5

Três soluções possíveis (assumindo que cada linha é um conjunto de dígitos somente ):

Para shells como ksh, bash, zsh:

printf '%08x\n' $(<infile)

Apenas para bash

<file.txt mapfile -t arr;   printf '%08x\n' "${arr[@]}" 

Para shells mais simples: dash (o padrão sh em sistemas baseados em Debian), ash (shell emulado em busybox), yash e alguns shells padrão no AIX e Solaris:

printf '%08x\n' $(cat infile)

Na verdade, para um shell como a versão de herança (como o Bourne) ele precisa ser escrito como (o que funciona em todos os shells do posix listados acima, mas eu recomendo strongmente que não o use ) :

$ printf '%08x\n' 'cat infile'

Resposta para EDITAR # 1

Entenda que um valor hexadecimal de 80000000 causará estouro em um computador de 32 bits (não é comum nos dias de hoje, mas é possível). Verifique se echo "$((0x80000000))" não imprime um valor negativo.

$ for i in $(<infile); do printf '%08x\n' "$(($i+0x80000000))"; done
80020000
80030000
80040000
80050000
80060000
    
por 21.07.2018 / 16:11
4

Usando awk :

$ awk '/[0-9]/ { printf("%08x\n", $0) }' file
00020000
00030000
00040000
00050000
00060000
    
por 21.07.2018 / 16:33
2

Ainda outro one-liner. Ainda não python, mas que permite comentários, linhas vazias e tudo o que no arquivo, e só imprime o resultado para as linhas que contêm apenas um número.

perl -ne '/^(\d+)$/ && printf "%08x\n", $1'  $your_file

Dado um arquivo como este:

$ cat $your_file
# some numbers,
131072
196608

262144
327680
393216

and empty lines
and whatever...

Imprime

00020000
00030000
00040000
00050000
00060000
    
por 21.07.2018 / 20:34
2

Usando julia

$ julia -e 'function hexadd(x) hex(( x + 0x80000000),8) end ; output = open("output.txt","w") ; open("test.txt") do inputfile for num in eachline(inputfile) write(output,"$(hexadd(parse(Int,num)))\n") end end'

Deveria ser mais fácil ler multilinhas:

function hexadd(x)
    hex(( x + 0x80000000),8)
end
output = open("output.txt","w")
open("test.txt") do inputfile
    for num in eachline(inputfile)
        write(output,"$(hexadd(parse(Int,num)))\n")
    end
end
  • hex( value, pad) converte um valor para hexadecimal e adiciona preenchimento conforme necessário.
    hexadd requer número inteiro como entrada, portanto convertemos cadeias (saída de eachline ) em Int com parse(Int,"string") e usamos isso em nossa função .
  • julia -e avalia uma expressão.
  • julia pode ser instalada nativamente no fedora, ubuntu

Usando dc:

$ dc -f test.txt -e '16o16i[80000000+psaz1<r]dsrx80000000+p' > output.txt

Explicação:

  • dc -f test.txt -e '16o 16i [80000000 + p sa z 1 <r] sr z 1 <r 80000000 + p' > output.txt
  • -f file envia o conteúdo do arquivo para a pilha
  • -e executar expressão
  • 16o convert saída para base 16
  • 16i assume a entrada na base 16. Isso acontece depois de ler o arquivo, então o arquivo foi lido na base 10. Mais explicitamente eu poderia fazer dc -e '10i' -f file -e '16 i 8000000'
  • [...] envia uma string para a pilha. Esta string será usada como uma macro.
  • 80000000 + adiciona o topo de pilha atual e 80000000 hexagonal. Empurre o resultado para o topo da pilha.
  • p Imprime o topo da pilha atual, sem estourar. Apenas opção de impressão que imprime uma nova linha.
  • sa Pop e armazena o topo da pilha no registro 'a'. Nunca é usado, apenas uma maneira de se livrar do topo do saco.
  • z O topo da pilha atual agora tem a profundidade da pilha. Necessário para terminar a chamada recursiva.
  • 1 empurra 1 para o topo da pilha. Útil em comparação com a profundidade da pilha (z) pressionada anteriormente.
  • <r compara 2 valores da pilha, se 2 for menor que 1, execute o registro 'r'. Com efeito, compare a profundidade da pilha e '1'.
  • sr pop e armazena no registro 'r'. Agora a macro está no registro 'r' e será executada enquanto a profundidade da pilha for maior que 1. Exceto que nada a chamou ainda.
  • d Duplica o topo da pilha e empurre.
  • x Executa o topo da pilha como macro.
  • d sr x Duplicar macro e push, agora pilha tem 2 cópias, pop e cópia da loja para registrar, estalar e executar a segunda cópia ...
  • Então, empurre a profundidade da pilha e 1, compare e execute, e para o último elemento, adicione novamente o valor hexadecimal e imprima.
por 22.07.2018 / 09:34
0

Você pode usar a biblioteca de Velud do awk:

$ velour '{print n_baseconv($0, 10, 16)}' test.txt
20000
30000
40000
50000
60000
    
por 22.07.2018 / 06:44