Awk 如何使用grep对列表进行排序,以根据预定义列表显示唯一出现的次数?

Awk 如何使用grep对列表进行排序,以根据预定义列表显示唯一出现的次数?,awk,grep,Awk,Grep,假设我有一个列表,看起来像这样 example.txt: 2010-01-06 15:03:14 57.55.24.13 user1 2010-01-07 20:02:14 69.54.12.36 user2 2010-01-08 12:34:34 127.21.159.2 user3 2010-01-08 02:43:45 116.40.11.179 user1 user1 user2 user3 列表中有一组给定的用户和他们使用的ip地址。我想做的是找到每个用户登录的唯一IP地址的数量

假设我有一个列表,看起来像这样

example.txt:

2010-01-06 15:03:14 57.55.24.13 user1
2010-01-07 20:02:14 69.54.12.36 user2
2010-01-08 12:34:34 127.21.159.2 user3
2010-01-08 02:43:45 116.40.11.179 user1 
user1
user2
user3
列表中有一组给定的用户和他们使用的ip地址。我想做的是找到每个用户登录的唯一IP地址的数量。因此,在前面的示例中,user1将返回值2。但是,如果user1从116.40.11.179再次登录,结果仍然是2,因为它不是唯一的ip

我试着列出用户名

userlist.txt:

2010-01-06 15:03:14 57.55.24.13 user1
2010-01-07 20:02:14 69.54.12.36 user2
2010-01-08 12:34:34 127.21.159.2 user3
2010-01-08 02:43:45 116.40.11.179 user1 
user1
user2
user3
然后我试着用类似的东西把它传给grep

grep example.txt | uniq -c | wc -l < userlist.txt
grep example.txt | uniq-c | wc-l
但这显然不是很好。有什么想法吗

awk '
{
    u = $4
    ip = $3
    if (!s[u,ip]++)
        cnt[u]++
}
END {
    for (u in cnt)
        print u, cnt[u]
}
' input.file
输出

user1 2
user2 1
user3 1

你能试试下面的吗

awk '
!seen[$NF OFS $(NF-1)]++{
  user[$NF]++
}
END{
  for(key in user){
    print key,user[key]
  }
}
'  Input_file
输出如下

user1 2                                                                                                                       
user2 1                                                                                                                       
user3 1 

对于阵列阵列,使用GNU awk:

$ awk '{usrs_ips[$4][$3]} END{for (usr in usrs_ips) print usr, length(usrs_ips[usr])}' file
user1 2
user2 1
user3 1
使用支持长度(数组)的awk:

对于任何awk:

$ sort -k4,4 file | awk '
    $4 != prev { if (NR>1) print prev, cnt; prev=$4; delete seen; cnt=0 }
    !seen[$3]++ { cnt++ }
    END { print prev, cnt }
'
user1 2
user2 1
user3 1

最后两个解决方案比第一个和目前发布的其他解决方案都有好处,它们没有将每个用户+ip组合存储在内存中,但这只有在输入文件很大的情况下才有意义

执行此操作的工具是uniq。您需要应用uniq两次:第一次按用户和IP对example.txt的条目进行分组,第二次用于计数

所以不需要在AWK中重新编码,即使这可以以非常漂亮的方式完成。但是,我将使用AWK对字段进行重新排序:

awk '{print $4, $3}' example.txt | sort | uniq | awk '{print $1}' | uniq -c

不需要单独的userlist.txt文件。

一个非
awk
示例,使用GNU,这是一个非常有用的工具,用于执行以下列数据组的操作:

$ datamash -Ws -g4 countunique 3 < example.txt
user1   2
user2   1
user3   1
$datamash-Ws-g4 countunique 3

对于第4列中具有相同值的每个组,它将在第3列中打印唯一出现的值的数量。

请在您的问题中提及预期的输出,然后让我们知道。@RavinderSingh13输出将是(#出现次数)因此,对于我的代码示例,应该是user12或user1,无论哪个更有效,其他人的答案也有效,但他们发布得更快。Ryan Ravinder和@slitvinov的解决方案是相同的,只是slitvinov使用了两个变量来保存$NF和$(NF-1)的值,将测试/条件放在操作区域而不是条件区域,并且不使用惯用的
!在测试中看到[keys]+
if(!((u,ip)in s)){s[u,ip];cnt[u]+}
通常/习惯性地写为
if(!看到[u,ip]+){cnt[u]+}
sort | uniq
=
sort-u
如果首先使用
sort-k4,4-k3,3-u文件| awk'{print$4}进行排序,则可以进一步减少对awk的管道和调用事实上你根本不需要awk:
sort-k4,4-k3,3-u文件| cut-d'-f4 | uniq-c
效率更高,因为
cut
awk
每输入行的工作量要少得多。不错的方法,顺便说一句。@EdMorton:这太棒了!顺便说一下,我没想到你会提出一个无awk的解决方案。我使用awk是为了可读性。我只使用最适合这项工作的工具(sed、grep、cut等等),只是当人们在这里发布关于操纵文本的问题时,通常是为了一些非琐碎的东西,然后最好的解决方案通常是awk。因此,从我对通常标有awk:-)的问题的回答中,您对我使用的工具有一个偏颇的看法。在这种情况下,我只是没有首先想到排序|切割| uniq
方法!