Considere este arquivo:
#!/usr/bin/env bash
cat > example_file.txt <<EOL
TITLE something
some data
some data
some data
TITLE something else
some other data
TITLE some more
some other data
some other data
some other data
TITLE extra info
some more data
some more data
EOL
Eu preciso adicionar uma nova coluna que:
- conta o número de linhas,
- volta a 1 após uma ocorrência de
/^TITLE/
, - começa na parte inferior do arquivo e segue para cima,
Basicamente, o resultado deve se parecer com:
TITLE something,4
some data,3
some data,2
some data,1
TITLE something else,2
some other data,1
TITLE some more,4
some other data,3
some other data,2
some other data,1
TITLE extra info,3
some more data,2
some more data,1
PS você pode supor que:
- o arquivo sempre começa com uma linha correspondente
/^TITLE/
- o arquivo sempre termina com uma linha que não corresponde
/^TITLE/
- não há duas linhas consecutivas correspondentes
/^TITLE/
Editar:
Resultados até agora
em um arquivo de 100 MB:
@Yarom
time tac trial.txt | awk 'BEGIN{x=0} {x++;{if ($1 !~/^pattern/) printf "%s,%s\n",$0,x;else if ($1 ~/^pattern/) {printf "%s,%s\n",$0,x;x=0}}}' | tac > trial2.txt
real 0m0,896s
@bac0n
time awk '{ a[i++]=$0 } END { while (i--) { a[i]=a[i] "," ++j; if (a[i] ~ /^pattern/) { j=0 } }; for (i=0; i<NR; i++) { print a[i] } }' trial.txt > trial2.txt
real 0m0,830s
@olivo:
time awk -v RS='^pattern' -v FS='\n' '
{
for(i=NF-1;i>0;i--)
printf "%s,%d\n",$i,i;
printf RT
}' trial.txt > trial2.txt
real 0m2,343s
@steeldriver
time awk -vRS='\n(^pattern|$)' -F'\n' -vOFS=, '
NR>1 {$1 = "^pattern" $1}
{for(i=1;i<=NF;i++) print $i, NF-i+1}
' trial.txt > trial2.txt
real 0m1,889s
usando mawk em vez de awk, recebo:
mawk: program limit exceeded: maximum number of fields size=32767
Consegui compilar o seguinte one-liner:
Vou explicar um pouco mais:
tac
- inverter a ordem das linhas (gato reverso).awk
- se a primeira coluna não forTITLE
avançar o contador, seTITLE
imprimir a contagem atual e redefinir para 0.tac
- inverta de volta.Resultados:
Boa sorte!
Usando awk:
Isso depende do separador de registro
RS
e do separador de campoFS
que são definidos para definir o valor inicial correto para o contadori
.As únicas instruções imprimem cada campo com o contador e o terminador de registro
RT
associado aRS
.Esta solução tem a vantagem de analisar o arquivo apenas uma vez e não requer colocar o arquivo inteiro na memória.
exemplo.awk
Exemplo
Resultado
Você pode tratar cada bloco como um registro e cada linha como um campo - dessa forma, você pode obter a contagem regressiva por bloco sem reverter o arquivo ou carregar mais de um bloco na memória.
Como seus blocos são delineados por um cabeçalho em vez de um rodapé, é necessário um pouco de hackers para lidar com o primeiro e o último registros. O melhor que consigo fazer é:
Isso deve ser válido em ambos
gawk
emawk
. Suspeito que ele funcionará significativamente mais rápido na sobrecarga inferiormawk
;gawk
a velocidade pode ser comparável se você definir a localidade para C/POSIX, ou sejaLC_ALL=C awk '...'