A abordagem simples: Use ex
para modificar as linhas e passar todo o buffer (arquivo modificado) através de bc
. Em seguida, imprima a versão modificada.
printf '%s\n' '%s:.*:&/8640000+719529:' 0a scale=10 . '%!bc' %p 'q!' | ex file.txt
Saída no seu arquivo de amostra:
735235.0000000000
735235.0000001157
735235.0000002314
735235.0000003472
735235.0000004629
Ou para salvar as alterações, em vez de apenas imprimi-las:
printf '%s\n' '%s:.*:&/8640000+719529:' 0a scale=10 . '%!bc' x | ex file.txt
Explicação:
Para ver quais comandos são passados para ex
, execute o comando printf
sozinho:
$ printf '%s\n' '%s:.*:&/8640000+719529:' 0a scale=10 . '%!bc' %p 'q!'
%s:.*:&/8640000+719529:
0a
scale=10
.
%!bc
%p
q!
Vamos dividi-los como ex
agora. O primeiro é bastante complexo, então vou formatar a explicação especialmente:
%s:.*:&/8640000+719529:
% - For every line of the buffer (file)
s - Run a substitute command
: - Using ':' as the regex delimiter
.* - Match each entire line
: - and replace with
& - The entire line, followed by
/8640000+719529 - this text
: - End command
0a
significa "acrescentar texto após a linha 0", em outras palavras, no início do buffer (arquivo).
O texto scale=10
é o texto literal a ser adicionado.
O .
em uma linha por si só encerra o comando "append".
O comando %!bc
passa o conteúdo de todo o buffer como entrada padrão para o comando externo bc
e substitui todo o buffer pela saída que é produzida.
O %p
significa imprimir todo o buffer (para a saída padrão).
q!
significa sair sem salvar as alterações.
Se você tem um arquivo muito, muito grande , nas dezenas de milhões de linhas, isso aparentemente causa problemas. Eu pesquisei possíveis soluções para isso usando ex
e há algumas maneiras que poderia ser feito, mas eu finalmente descartei essa abordagem em favor de uma muito, muito mais simples, que ainda usa apenas ferramentas especificadas POSIX .
Use split
para dividir seu arquivo em partes e execute o comando especificado anteriormente em cada bloco e cat
a saída resultante todos juntos:
split -l 1000000 -a 3 file.txt myprefix.
for f in myprefix.???; do
printf '%s\n' '%s:.*:&/8640000+719529:' 0a scale=10 . '%!bc' %p 'q!' |
ex "$f"
done > myoutputfile.txt
rm myprefix.???
O comando split
é usado aqui para dividir file.txt
em blocos, cada um com até um milhão de linhas (com o restante colocado em um arquivo também, é claro). Como -a 3
é especificado, o sufixo nos blocos terá 3 caracteres. myprefix.aaa
, myprefix.aab
, etc.
Cada arquivo pode ser processado por ex
individualmente e sem necessidade de salvar as alterações, uma vez que apenas redirecionaremos a saída desse loop inteiro para myoutputfile.txt
(e, em seguida, removeremos os arquivos do fragmento, para limpeza).