Substituir campo do contador em arquivo grande com valor iterado

0

Eu tenho um enorme arquivo de texto com cerca de 70 mil linhas nele. Meu objetivo é ler esse arquivo, corresponder a um padrão ("Contagem") e adicionar ou substituir seu valor por um número repetido.

O que estou fazendo é:

  1. Lendo arquivo.
  2. Grep para o padrão Contagem.
  3. Se corresponder, exclua o padrão.
  4. Anexar o padrão desejado (Contagem = $ i) nessa linha.
  5. Incrementar variável i.

Aqui está o código

line_count=0
i=0
while read line
do
        line_count=$((line_count+1))
        if echo "$line" | grep -q "Count"
        then
                sed -i "$line_count d" /tmp/$rand_file1
                sed -i "$line_count i Count = $i" /tmp/rand_file1
                i=$((i+1))
        fi
done </tmp/rand_file1

A técnica acima leva cerca de 25 minutos para ser concluída. Existe uma maneira de reduzir esse tempo, pois trabalharei com arquivos de dados maiores?

Abaixo está o padrão e o arquivo de entrada e a saída esperada:

Arquivo de entrada

Count
Name = Sarah
ID = 113
PhNo =

Count
Name = John
ID = 787
PhNo =

Count = 123
Name = Mike
ID = 445
PhNo =

Count Now
Name = Max
ID = 673
PhNo =

Arquivo de saída esperado

Count = 1
Name = Sarah
ID = 113
PhNo =

Count = 2
Name = John
ID = 787
PhNo =

Count = 3
Name = Mike
ID = 445
PhNo =

Count = 4
Name = Max
ID = 673
PhNo =
    
por manu ks 16.04.2018 / 08:58

6 respostas

0

Substituindo linhas com Contagem com Contagem = sua Ocorrência

Assumindo que Count é a primeira palavra na linha

awk -v c=1 'sub(/^Count.*/, "Count = " c) {c++}; {print}' /tmp/rand_file1

Assumindo que Contagem é a primeira palavra na linha, mas pode ser precedida com zero ou mais espaço em branco, espaços em branco não são preservados.

awk -v c=1 'sub(/^[[:blank:]]*Count.*/, "Count = " c) {c++}; {print}' /tmp/rand_file1
    
por 16.04.2018 / 09:21
3

A análise de um arquivo de texto no shell é muito lenta e extremamente propensa a erros. Você está executando grep uma vez por linha no arquivo de entrada e sed duas vezes para cada linha que contém Count . Evite fazer isso.

Tanto quanto eu posso ver, isso pode ser substituído por

awk '$1 == "Count" { printf("Count = %d\n", ++i); next } { print }' rand_file1 >rand_file1.new

Isso gera as linhas Count = com o incremento correto quando atinge uma linha cujo primeiro campo é exatamente Count e passa todas as outras linhas como estão.

Alternativamente,

awk '$1 == "Count" { $0 = sprintf("Count = %d", ++i) } { print }' rand_file1 >rand_file1.new

que modifica o valor $0 (a linha de entrada) e imprime todas as linhas com um único print .

Esta última variação pode ser encurtada para

awk '$1 == "Count" { $0 = sprintf("Count = %d", ++i) } 1' rand_file1 >rand_file1.new

Veja também " Por que usar um loop de shell para processar texto considerado uma prática ruim? ".

    
por 16.04.2018 / 09:19
3

Abordagem curta awk :

awk '$1 == "Count"{ $0 = "Count = "++i }1' file

A saída:

Count = 1
Name = Sarah
ID = 113
PhNo =

Count = 2
Name = John
ID = 787
PhNo =
    
por 16.04.2018 / 09:21
2

A resposta obrigatória perl :

perl -pe 's{^Count\b.*}{"Count = " . ++$i}e'
    
por 16.04.2018 / 09:52
0

Arquivos de entrada de amostra pendentes, acho que isso deve funcionar:

gawk '($1=="Count"){print "Count = " (++i); next;} 1' /tmp/rand_file1

Uma breve explicação:

  • nas linhas que têm Count como o primeiro campo: imprima uma nova instrução de contagem e um número de incremento. ++i começará em 1, i++ começará em 0. Nesse caso, pule também o restante do processamento e continue na linha de entrada next .

  • em todas as linhas ( 1 ): execute a ação padrão, que é imprimir a linha de entrada.

Isso deve ser mais rápido, pois ele toca cada linha de entrada apenas uma vez, na sua solução existente, uma correspondência para Count copia todo o arquivo.

    
por 16.04.2018 / 09:11
0

Usando sed , com seq inserido para a iteração:

t='Count'
seq -f "$t = %g" 70000 | sed -i -e "/^$t/R /dev/stdin" -e "/^$t/d" /tmp/rand_file1

Notas:

  • O comando sed 'co_de% ead não funcionará nas chaves R , então dois {} s são necessários.
  • O -e pode ser qualquer número grande o suficiente. Quando 70000 parar, o mesmo acontece com sed , portanto, os valores mais altos nem serão criados.
por 20.04.2018 / 17:27