Как я могу напечатать номер строки записи в awk? - PullRequest
0 голосов
/ 24 января 2019

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

Пример данных (включая номера строк):

1 | data1 - good
2 |    foo bar
3 |
4 | data2 - bad
5 |    foo bar
6 |    pet cat
7 |    name snuggles
8 |
9 | data3 - good
10|    foo bar
11|    color blue

Пример кода:

BEGIN {RS =""; FS="\n"; ORS="\n\n"; OFS=""; x=0}
{
  { x += NF + 1; }
  { if ($1 ~ /bad/) { next; } }
  { print "[", x - NF, "]\n", $0; }
}

Вывод, который я ищу, будет примерно таким:

[1]
data1 - good
    foo bar

[9]
data3 - good
    foo bar
    color blue

Есть ли лучший способ сделать это, чего я не вижу?

Ответы [ 4 ]

0 голосов
/ 24 января 2019

Если Perl является опцией, вы можете попробовать ниже

$ cat caffein.txt
data1 - good
   foo bar

data2 - bad
   foo bar
   pet cat
   name snuggles

data3 - good
   foo bar
   color blue

$ perl -0777 -ne ' s/^/++$x." "/mge; while(/(^\d+)(\s*data.+?good.+?)(\n\d+\s+\n\d+\s+|\Z)/gms) { $x="[$1] $2\n\n";$x=~s/^\d+/ /mg; print $x } ' caffein.txt
[1]  data1 - good
     foo bar

[9]  data3 - good
     foo bar
     color blue


$

или с отрицательным взглядом на несоответствие "плохо"

$ perl -0777 -ne ' s/^/++$x." "/mge; while(/(^\d+)(\s*data.+?(?!bad).+?)(\n\d+\s+\n\d+\s+|\Z)/gms) { $x="[$1] $2\n\n";$x=~s/^\d+/ /mg; print $x } ' caffein.txt
0 голосов
/ 24 января 2019

В целом, я думаю, что ваш подход хорош, и не считаю его хаккейным.

Вы можете рассмотреть некоторые незначительные изменения, чтобы сделать его немного проще:

BEGIN {RS =""; FS="\n"; ORS="\n\n"; OFS=""; x=1}
!($1 ~ /bad/) { print "[", x, "]\n", $0; }
{ x += NF + 1; }
0 голосов
/ 24 января 2019

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

$ cat tst.awk
BEGIN { RS=""; ORS="\n\n"; FS="\n" }
{
    nr += prevNf + 1
    if ($1 ~ /good/) {
        print "[" nr "]\n" $0
    }
    prevNf = NF
}

$ awk -f tst.awk file
[1]
data1 - good
   foo bar

[9]
data3 - good
   foo bar
   color blue

, но есть альтернатива:

$ cat tst.awk
!NF { prt(); next }
{
    nrs[++numLines] = NR
    rec[numLines]   = $0
}
END { prt() }

function prt(   lineNr) {
    if (rec[1] ~ /good/) {
        printf "[%d]\n", nrs[1]
        for (lineNr=1; lineNr<=numLines; lineNr++) {
            print rec[lineNr]
        }
        print ""
    }
    delete rec
    numLines = 0
}

$ awk -f tst.awk file
[1]
data1 - good
   foo bar

[9]
data3 - good
   foo bar
   color blue

С помощью вышеописанного вы можете сделать больше, чем просто тестироватьхорошо это или плохо только в одной строке, и вы можете напечатать номер строки ввода для всех или любых строк каждой записи, если хотите.

0 голосов
/ 24 января 2019

Не могли бы вы попробовать один раз, протестированы только с вашими образцами.

awk '
/data[0-9]+/{
  flag=$NF=="bad"?"":1
  count=""
}
flag && NF>2{
  if(++count==1){
    print "["$1"]"
    sub(/.*\| /,"")
  }
  sub(/.*\|/,"")
  print
}'   Input_file
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...