![如何对同一个文件运行 awk 两次](https://linux22.com/image/60994/%E5%A6%82%E4%BD%95%E5%AF%B9%E5%90%8C%E4%B8%80%E4%B8%AA%E6%96%87%E4%BB%B6%E8%BF%90%E8%A1%8C%20awk%20%E4%B8%A4%E6%AC%A1.png)
我有一个包含 user_id 的日志文件和另一个包含竞赛结果的列。我想:
- 查找所有获胜用户的user_id
- 给定这些 user_id,返回这些用户的所有日志条目
例子:
日志.csv
id,user_id,winner,page_id
1,user_1,win,1
2,user_1,,10
3,user_2,,1
4,user_2,,2
5,user_4,win,10
6,user_5,,2
7,user_5,win,3
给定这样的日志文件,我目前将其分为两步:
第 1 步:返回提及“win”一词的每一行
/win/ {
FS=","
# To make unique, store user_id's in array
n[$2] = 0
}
# Print the unique array keys
END{
for (x in n)
print x
}
这产生:
user_1
user_4
user_5
我将此输出保存在文件中output.txt
然后,我将该文件和原始日志文件传递到另一个 awk 文件中:
NR == FNR{
n[$1] = 0 # Set the user ID to the array
next # Go to the next file
}
{
FS=","
if($2 in n){
print $0
}
}
这将返回正确的输出(获胜的每个 user_id 的所有行):
1,user_1,win,1
2,user_1,,10
5,user_4,win,10
6,user_5,,2
7,user_5,win,3
有没有更优雅的方法来做到这一点?使用单个 awk 文件?
答案1
为时已晚,但为了后代,我想指出你可以这样做:
awk '
{
# do first pass stuff
}
END
{
while(getline < FILENAME)
{
# do second pass stuff
}
close(FILENAME)
}
' file
如果您想执行更多遍,可以close(FILENAME)
在第一个 while 循环之后执行第二个循环。
答案2
我会使用两个数组:
awk -F, '{a[$0]=$2;if($3=="win")b[$2]++}END{for(i in a){if(b[a[i]])print i}}'
答案3
有没有更优雅的方法来做到这一点?
是的,当然有。只需在同一个文件上运行 Awk 两次(正如您在标题中所说)。
awk -F, '$3=="win"{won[$2]} FNR==NR{next} $2 in won' log.csv log.csv
答案4
我的填充方式grep
比所以更快awk
,如果你有的GNU grep
话Perl 扩展你可以试试
fgrep -f <(grep -oP "[^,]*(?=,win)" log.csv) log.csv
没有的话perl.ext
你就必须grep
通过管道输出cut
fgrep -f <(grep win log.csv | cut -d, -f2) log.csv
或者使用sed
(似乎比上面快一点grep
| cut
)
fgrep -f <(sed -n '/win/s/^[^,]*,\([^,]*\).*/\1/p' log.csv) log.csv