如何使用 gawk 多次传递?
How to use multiple passes with gawk?
我正在尝试使用 CYGWIN 中的 GAWK 来处理 csv 文件。第 1 遍找到最大值,第 2 遍打印匹配最大值的记录。我正在使用 .awk 文件作为输入。当我使用手册中的文本时,它在两次通过时都匹配。我可以使用 IF 形式作为解决方法,但这迫使我在每个模式匹配中使用 IF,这有点痛苦。知道我做错了什么吗?
这是我的 .awk 文件:
pass == 1
{
print "pass1 is", pass;
}
pass == 2
{
if(pass == 2)
print "pass2 is", pass;
}
这是我的输出(输入文件只是“hello”):
hello
pass1 is 1
pass1 is 2
hello
pass2 is 2
这是我的命令行:
gawk -F , -f test.awk pass=1 x.txt pass=2 x.txt
如有任何帮助,我将不胜感激。
(g)awk 解决方案可能如下所示:
awk 'FNR == NR{print "1st pass"; next}
{print "second pass"}' x.txt x.txt
(如有必要,请将 awk
替换为 gawk
。)
比方说,你想在文件 x.txt
的第一列中搜索最大值,然后在第一列中打印所有具有该值的行,你的程序可能看起来像这样(感谢 Ed Morton 一些提示,见评论):
awk -F"," 'FNR==NR {max = ( (FNR==1) || ( > max) ? : max ); next}
==max' x.txt x.txt
x.txt
的输出:
6,5
2,6
5,7
6,9
是
6,5
6,9
这是如何工作的?变量 NR
随着每条记录不断增加,而 FNR
在读取新文件时重置为 1
。因此,FNR==NR
仅适用于处理的第一个文件。
所以... F.Knorr 准确简洁地回答了您的问题,他应该得到一个大大的绿色勾号。 NR==FNR
正是您要找的秘方。
但这里有一个不同的方法,以防万一多遍的事情被证明是有问题的。 (也许您正在从慢速驱动器、USB 记忆棒、网络、DAT 磁带等读取文件)
awk -F, '>m{delete l;n=0;m=}m=={l[++n]=[=10=]}END{for(i=1;i<=n;i++)print l[i]}' inputfile
或者,为了便于阅读,将空格分开:
BEGIN {
FS=","
}
> max {
delete list # empty the array
n=0 # reset the array counter
max= # set a new max
}
max== {
list[++n]=[=11=] # record the line in our array
}
END {
for(i=1;i<=n;i++) { # print the array in order of found lines.
print list[i]
}
}
使用与 F.Knorr 测试相同的输入数据,我得到相同的结果。
这里的想法是一次通过文件。我们将与最大值匹配的每一行记录在一个数组中,如果我们遇到超过最大值的值,我们将清除数组并重新开始收集行。
这种方法在 CPU 和内存(取决于数据集的大小)上较重,但作为单次传递,它可能在 IO 上较轻。
这里的问题是换行符对 awk 很重要。
# This does what I should have done:
pass==1 {print "pass1 is", pass;}
pass==2 {if (pass==2) print "pass2 is", pass;}
# This is the code in my question:
# When pass == 1, do nothing
pass==1
# On every condition, do this
{print "pass1 is", pass;}
# When pass == 2, do nothing
pass==2
# On every condition, do this
{if (pass==2) print "pass2 is", pass;}
使用 pass==1,pass==2 不那么优雅,但它有效。
我正在尝试使用 CYGWIN 中的 GAWK 来处理 csv 文件。第 1 遍找到最大值,第 2 遍打印匹配最大值的记录。我正在使用 .awk 文件作为输入。当我使用手册中的文本时,它在两次通过时都匹配。我可以使用 IF 形式作为解决方法,但这迫使我在每个模式匹配中使用 IF,这有点痛苦。知道我做错了什么吗?
这是我的 .awk 文件:
pass == 1
{
print "pass1 is", pass;
}
pass == 2
{
if(pass == 2)
print "pass2 is", pass;
}
这是我的输出(输入文件只是“hello”):
hello
pass1 is 1
pass1 is 2
hello
pass2 is 2
这是我的命令行:
gawk -F , -f test.awk pass=1 x.txt pass=2 x.txt
如有任何帮助,我将不胜感激。
(g)awk 解决方案可能如下所示:
awk 'FNR == NR{print "1st pass"; next}
{print "second pass"}' x.txt x.txt
(如有必要,请将 awk
替换为 gawk
。)
比方说,你想在文件 x.txt
的第一列中搜索最大值,然后在第一列中打印所有具有该值的行,你的程序可能看起来像这样(感谢 Ed Morton 一些提示,见评论):
awk -F"," 'FNR==NR {max = ( (FNR==1) || ( > max) ? : max ); next}
==max' x.txt x.txt
x.txt
的输出:
6,5
2,6
5,7
6,9
是
6,5
6,9
这是如何工作的?变量 NR
随着每条记录不断增加,而 FNR
在读取新文件时重置为 1
。因此,FNR==NR
仅适用于处理的第一个文件。
所以... F.Knorr 准确简洁地回答了您的问题,他应该得到一个大大的绿色勾号。 NR==FNR
正是您要找的秘方。
但这里有一个不同的方法,以防万一多遍的事情被证明是有问题的。 (也许您正在从慢速驱动器、USB 记忆棒、网络、DAT 磁带等读取文件)
awk -F, '>m{delete l;n=0;m=}m=={l[++n]=[=10=]}END{for(i=1;i<=n;i++)print l[i]}' inputfile
或者,为了便于阅读,将空格分开:
BEGIN {
FS=","
}
> max {
delete list # empty the array
n=0 # reset the array counter
max= # set a new max
}
max== {
list[++n]=[=11=] # record the line in our array
}
END {
for(i=1;i<=n;i++) { # print the array in order of found lines.
print list[i]
}
}
使用与 F.Knorr 测试相同的输入数据,我得到相同的结果。
这里的想法是一次通过文件。我们将与最大值匹配的每一行记录在一个数组中,如果我们遇到超过最大值的值,我们将清除数组并重新开始收集行。
这种方法在 CPU 和内存(取决于数据集的大小)上较重,但作为单次传递,它可能在 IO 上较轻。
这里的问题是换行符对 awk 很重要。
# This does what I should have done:
pass==1 {print "pass1 is", pass;}
pass==2 {if (pass==2) print "pass2 is", pass;}
# This is the code in my question:
# When pass == 1, do nothing
pass==1
# On every condition, do this
{print "pass1 is", pass;}
# When pass == 2, do nothing
pass==2
# On every condition, do this
{if (pass==2) print "pass2 is", pass;}
使用 pass==1,pass==2 不那么优雅,但它有效。