Estou tentando criar um script de banco de dados a partir de um fluxo de rede. O fluxo de rede após ser fortemente sed descarta um arquivo de três colunas parecido com este chamado file.db
123.123.123.123, nome do computador, 110000103e21cc4
123.123.123.124,computador2,11000010416200f
123.123.123.1,computador3,110000106eb3f43
tentei usar esse comando gawk sem sucesso
gawk 'BEGIN {FS=OFS=","} {print $1,$2,strtonum("0x"$3)}' file.db
a saída acima é assim
123.123.123.123, nome do computador, 76561198025415874
123.123.123.124,computador2,76561198028824592
123.123.123.1,computador3,76561198076346171
no entanto, a saída deve ser convertida para este
123.123.123.123, nome do computador, 76561198025415876
123.123.123.124,computador2,76561198028824591
123.123.123.1,computador3,76561198076346179
a saída está sempre errada em uma pequena quantidade, então estou assumindo que alguma biblioteca no sistema não está correta ... aliás, este é um sistema embarcado em execução e eu sei que ele pode ser convertido porque eu fiz isso com bc, printf, etc etc
Como posso fazer isso funcionar
Responder1
Armazena internamente gawk
o valor convertido em um ponto flutuante de precisão dupla, portanto, a pequena discrepância é apenas um erro de arredondamento herdado de qualquer valor de ponto flutuante. Para obter resultados precisos, gawk
é necessário terceirizar o tratamento de números para outros comandos que suportam números de precisão arbitrários, como bc
.
No entanto, com a sintaxe atual, gawk
é impossível fazer uma análise complexa da linha de comando do shell dentro do gawk, portanto, seria necessário primeiro um auxiliar de script de shell. Vamos nomeá-lo bc.sh
:
#!/bin/bash
echo -e "ibase=16\n$1" | bc -q
Este script alimenta ibase=16
o primeiro argumento (número hexadecimal) em bc
, de modo que bc
gera o número decimal correspondente. Então gawk
seria chamado desta forma:
gawk 'BEGIN {FS=OFS=","} { "./bc.sh " toupper($3) | getline b; print $1,$2,b}' file.db
Isso diz gawk
para chamar o script de shell com $3 maiúsculo ( bc
não suporta valor hexadecimal minúsculo), armazenar o resultado na b
variável e imprimir todos os argumentos de uma só vez.
Cuidado, ./bc.sh
deve haver algum espaço anexado entre aspas duplas, caso contrário, ele tentará executar um arquivo inexistente, como ./bc.sh110000103E21CC4
.
Responder2
Eu olho para trás e a maneira como acabei fazendo isso é
criando um script bash como o chamado convert12345678.sh
#!/opt/bin/bash
(echo -e "ibase=16\nobase=0A" ; echo $1 | tr 'a-z' 'A-Z') | bc | tr "\n" " " | sed 's/\ //g'
e então fiquei boquiaberto com o que eu precisava dizer, como na operação (modifiquei fortemente esse programa desde então) era algo assim, e canalizei este programa, mas vou demonstrar a partir de um arquivo
gawk -F, '{printf("%s,%s,",$1,$2)};{system("/files/convert12345678 "$3)};{printf("\n")}' file.db
eu fiz isso dessa maneira, removendo a nova linha no script bash porque, honestamente, eu a mudei depois, o posicionamento de execução do script, então, dessa forma, eu não teria a nova linha interposta na saída imediatamente após a conversão, a menos que eu quisesse com imprimir