如何对同一个文件运行 awk 两次

如何对同一个文件运行 awk 两次

我有一个包含 user_id 的日志文件和另一个包含竞赛结果的列。我想:

  1. 查找所有获胜用户的user_id
  2. 给定这些 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 grepPerl 扩展你可以试试

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

相关内容