我该如何在awk中打印一条记录的行号?

3

我正在使用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; }
}

我要的输出结果应该像这样:
```html

我要的输出结果应该像这样:

```
[1]
data1 - good
    foo bar

[9]
data3 - good
    foo bar
    color blue

有没有更好的方法来完成这件事,我可能没想到?

4个回答

2
通常情况下,我认为你的方法是可行的,不会认为它是hackey。
您可以考虑进行一些微小的调整,使其更加简单:
BEGIN {RS =""; FS="\n"; ORS="\n\n"; OFS=""; x=1}
!($1 ~ /bad/) { print "[", x, "]\n", $0; }
{ x += NF + 1; }

1

请尝试以下步骤,仅使用您的样本进行测试。

awk '
/data[0-9]+/{
  flag=$NF=="bad"?"":1
  count=""
}
flag && NF>2{
  if(++count==1){
    print "["$1"]"
    sub(/.*\| /,"")
  }
  sub(/.*\|/,"")
  print
}'   Input_file

1

你的方法似乎不错,尽管我可能会稍微调整一下:

$ 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
如果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


$

或者使用负向先行断言来匹配不包含"bad"的内容

$ 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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接