AWK: добавьте количество строк *к следующему* происшествие шаблона (в огромном файле)

Рассмотрите этот файл:

#!/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

Я должен добавить новый столбец что:

  • считает количество строк,
  • возвращается к 1 после возникновения /^TITLE/,
  • начинает с нижней части файла и прокладывает себе путь вверх,

В основном результат должен быть похожим:

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

P.S. можно предположить что:

  • файл всегда запускается с соответствия строки /^TITLE/
  • файл всегда заканчивается строкой, не соответствующей /^TITLE/
  • нет никаких двух последовательных соответствий строк /^TITLE/

Править:

Результаты до сих пор

на файле 100 МБ:

@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

@oliv:

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

с помощью mawk вместо awk, я добираюсь:

mawk: program limit exceeded: maximum number of fields size=32767
0
задан 24 September 2019 в 21:11

4 ответа

пример example.awk

#!/bin/awk -f

{ a[i++]=[110] } END {
    while (i--) {
        a[i]=a[i] "," ++j
        if (a[i] ~ /^TITLE/) { j=0 }
    }
    for (i in a) { print a[i] }
}

awk -f example.awk example.txt

Вывод

TITLE something,4
DATA some data,3
DATA some data,2
DATA some data,1
TITLE something else,2
DATA some other data,1
TITLE some more,4
DATA some other data,3
DATA some other data,2
DATA some other data,1
TITLE extra info,3
DATA some more data,2
DATA some more data,1
1
ответ дан 23 October 2019 в 00:42

Мне удалось скомпилировать следующую остроту:

tac so_count.txt | awk 'BEGIN{x=0} {x++;{if ($1 != "TITLE") printf "%s,%s\n",[110],x;else if ($1 == "TITLE") {printf "%s,%s\n",[110],x;x=0}}}' | tac

я объясню немного далее:

  • tac - инвертируют порядок строк (инвертируйте кошку).
  • awk - если первый столбец не TITLE, совершенствуют счетчик, если TITLE печатают текущее количество и сбрасывают назад к 0.
  • tac - инвертируют его назад.

Результаты:

TITLE something,4
DATA some data,3
DATA some data,2
DATA some data,1
TITLE something else,2
DATA some other data,1
TITLE some more,4
DATA some other data,3
DATA some other data,2
DATA some other data,1
TITLE extra info,3
DATA some more data,2
DATA some more data,1

Удачи!

2
ответ дан 23 October 2019 в 00:42

Вы могли рассматривать каждый блок как запись и каждую строку как поле - тот путь, можно свалить количество на блок или без инвертирования файла или без загрузки больше чем одного блока в память.

, поскольку Ваши блоки очерчены заголовком, а не нижним колонтитулом, немного хакерства требуется, чтобы обрабатывать первое последние записи. Лучшее, которое я могу придумать:

awk -vRS='\n(TITLE|$)' -F'\n' -vOFS=, '
  NR>1 {$1 = "TITLE" $1} # replace the RS that got stripped off
  {for(i=1;i<=NF;i++) print $i, NF-i+1}
' example_file.txt

Это должно быть допустимо и в gawk и в mawk. Я подозреваю, что это будет работать значительно быстрее в более низких издержках mawk; gawk скорость может быть сопоставимой при установке локали на C/POSIX т.е. LC_ALL=C awk '...'

2
ответ дан 23 October 2019 в 00:42

Используя awk:

awk -v RS='TITLE ' -v FS='\n' '
{
  for(i=NF-1;i>0;i--) 
    printf "%s,%d\n",$i,i; 
    printf RT
}' file

Это полагается на разделитель записей RS и разделителя полей FS, которые установлены установить правильное начальное значение к счетчику i.

единственные операторы печатают каждое поле со счетчиком и рекордным разделителем RT связанный с RS.

Это решение имеет преимущество, чтобы только проанализировать файл однажды и не требует для помещения целого файла в память.

2
ответ дан 23 October 2019 в 00:42

Другие вопросы по тегам:

Похожие вопросы: