我正在使用awk处理多行记录,其中每条记录的字段数未知。这有助于过滤非常大的文件中的记录,因此了解返回记录的行号将很有帮助。我尝试为每个记录赋予一个变量,但这似乎很麻烦,有没有更好的方法呢?
数据示例(包括行号):
{
user: {
street: '111 Cool Street'
}
}
代码示例:
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; }
}
有没有更好的方法可以做到这一点?
答案 0 :(得分:2)
总的来说,我认为您的方法很好,不会认为它是hackey。
您可能会考虑进行一些小的调整,以使其变得更简单:
BEGIN {RS =""; FS="\n"; ORS="\n\n"; OFS=""; x=1}
!($1 ~ /bad/) { print "[", x, "]\n", $0; }
{ x += NF + 1; }
答案 1 :(得分:1)
请您尝试一次,仅对样品进行测试。
awk '
/data[0-9]+/{
flag=$NF=="bad"?"":1
count=""
}
flag && NF>2{
if(++count==1){
print "["$1"]"
sub(/.*\| /,"")
}
sub(/.*\|/,"")
print
}' Input_file
答案 2 :(得分: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
使用上述方法,您不仅可以在一行上测试好坏,还可以做更多的事情,并且可以根据需要打印每条记录的所有行或任何行的输入行号。
答案 3 :(得分: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
$
或对于不匹配的“不良”具有否定的前瞻性
$ 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