Extrai dados numéricos do padrão complicado em um arquivo de texto simples e produz uma saída tabular

2

Esta é uma questão SOS. Meu professor me pediu para obter a saída de um código de simulação de longa duração que nos foi legado por um ex-post-doc (que me explicara seu funcionamento).

Eu fiz alguns testes em pequena escala e tudo correu bem. Então eu comecei a simulação completa cerca de um mês atrás e tem sido executado continuamente desde então. Mas apenas alguns minutos atrás, devido a alguns problemas de memória, o programa travou antes que pudesse gravar a saída tabular formatada em disco.

Felizmente, eu tinha ativado o eco de terminal dos resultados intermediários e defini meu histórico de rolagem para um valor maior. Consegui salvar a saída parcial digitando o modo de retrocesso e copiando todo o despejo de terminal em um arquivo de texto (e também fiz cópias de backup dele).

Agora, esta saída de terminal é bastante detalhada (intencionalmente definida para fins de depuração). A seguir, um instantâneo do arquivo de texto de saída de terminal recuperado (vamos chamá-lo de terminal_output.txt )

1 Linear search iteration no. 1 begins: Attempting to blah blah with 1 ...
2 blah blah 
3 blah 
4 blah blah blah
5 lorem ipsum 
.........
........
75 Success with 128 blah ....
76 blah blah
77 blah blah
78 result_flag: 1, exit_reason: 6
79 blah
80 Completed optimal computation with T_init = 25.00 degC & T_sink = 35.00 degC

E então esse padrão exato se repete. por exemplo,

81 Linear search iteration no. 2 begins: Attempting to blah blah with 1 ...
82 blah
......
95 Success with 307 blah ....
......
......
100 Completed optimal computation with T_init = 30.00 degC & T_sink = 40.00 degC

Meu requisito é extrair as seguintes informações para produzir uma saída tabular como:

25  35  128
30  40  307
...........
...........

i.e. o 1º & As colunas 2 são dos valores numéricos correspondentes a T_init e T_sink respectivamente, a partir dessas linhas começam com Completed . A terceira coluna é o valor numérico da linha que começa com Success (que é sempre 5 linhas antes de Completed , se isso ajudar). Qualquer separador entre as colunas é aceitável, seja espaços, tabulações ou vírgulas.

Eu desejo fazer isso de forma nativa usando os utilitários * nix padrão, como grep , sed e awk ou mesmo vi/vim . As linhas de um-cano unidas ou os scripts bash estão bem. Se necessário, estou aberto a usar python , perl ou outras linguagens de script também.

    
por Krishna 02.05.2018 / 16:46

3 respostas

2

É essencialmente uma questão de capturar as partes que você quer e descartar as partes que você não quer. Por exemplo, usando sed , você poderia capturar o valor inteiro Success e copiá-lo para o espaço de espera ( h ), recuperando e anexando-o ( G ) ao dígitos capturados da linha Completed :

sed -nE \
  -e '/Success/ {s/.* ([0-9]+).*//; h;}' \
  -e '/Completed/{G; s/.*T_init = ([0-9]+)\.00 degC & T_sink = ([0-9]+).*\n/  /; p;}
' terminal_output.txt

Perl fornece uma sintaxe um pouco mais expressiva, que IMHO é mais legível:

perl -lne '
  our $a = $1 if /Success.*?(\d+)/; print join " ", /(\d+)\.\d+/g, $a if /Completed/
' terminal_output.txt

produz a saída desejada

25 35 128
30 40 307
    
por 02.05.2018 / 17:21
0

compatível com POSIX sed :

grep -e 'Success' -e 'Completed' your_file | sed 'N;s/Success with \([[:digit:]]\+\).*T_init = \([^[:space:]]\+\).*T_sink = \([^[:space:]]\+\).*/  /;s/\.00//g'

GNU sed : (em que . não corresponde a \n em 4.2.2 no CentOS)

grep -e 'Success' -e 'Completed' your_file | sed 'N;s/Success with \([[:digit:]]\+\).*\n.*T_init = \([^[:space:]]\+\).*T_sink = \([^[:space:]]\+\).*/  /;s/\.00//g'

Grabs linhas contendo Success e Completed , em seguida, operando em duas linhas (maneira mais explícita do que o necessário) puxa os três campos que você gosta e os ordena em uma linha.

Isso trunca apenas .00 de qualquer número, deixando qualquer componente fracionário significativo sozinho (incluindo algo como 12.20 , ainda haveria o único zero à direita).

Advertência de que não funcionará se algumas dessas ... linhas contiverem Completed ou Success

    
por 02.05.2018 / 17:22
-1

Um rápido comando awk deve começar:

awk '$2 ~ /Success/{a=$4;next}; $2 ~ /Completed/{b=$8;c=$13;print a,b,c}' terminal_output.txt

Isso não funcionará se você tiver várias linhas Success antes de uma linha Completed , etc.

    
por 02.05.2018 / 17:10