awk或shell命令根据第4列中的值计算第1列中值的出现次数

时间:2018-04-14 06:58:49

标签: bash shell unix awk sed

我有一个包含以下记录的大文件:

jon,1,2,apple
jon,1,2,oranges
jon,1,2,pineaaple
fred,1,2,apple
tom,1,2,apple
tom,1,2,oranges
mary,1,2,apple

我想找到人的名字(第1栏中的名字)都有苹果和橘子。并且命令应该尽可能减少内存并且应该快速。任何帮助表示赞赏!

输出: awk / sed file => 2(琼和汤姆)

4 个答案:

答案 0 :(得分:3)

使用awk非常简单:

awk -F, \
    '$4 == "apple"   { apple[$1]++  }
     $4 == "oranges" { orange[$1]++ }
     END { for (name in apple) if (orange[name]) print name }' data

它在样本data文件上生成所需的输出:

jon
tom

是的,您可以将所有代码压缩到一行,缩短名称,否则会混淆代码。

另一种方法可以避免END阻止:

awk -F, \
    '$4 == "apple"   { if (apple[$1]++ == 0 && orange[$1]) print $1 }
     $4 == "oranges" { if (orange[$1]++ == 0 && apple[$1]) print $1 }' data

当第一次遇到给定名称的apple条目时,它会检查该名称是否(已经)具有oranges的条目,如果有,则打印出来;同样且对称,如果它第一次遇到给定名称的orange条目,它会检查该名称是否还有apple的条目,如果有,则打印出来。

Sundeep中的comment所述,它可以使用in

awk -F, \
    '$4 == "apple"   { if (apple[$1]++ == 0 && $1 in orange) print $1 }
     $4 == "oranges" { if (orange[$1]++ == 0 && $1 in apple) print $1 }' data

第一个答案也可以在in循环中使用END

请注意,所有这些解决方案都可以嵌入到一个脚本中,该脚本可以接受来自标准输入(管道或重定向文件)的数据 - 它们不需要两次读取输入文件。您将data替换为"$@"以处理文件名(如果已给出),或者如果未指定文件名则替换为标准输入。在可能的情况下,这种灵活性值得保留。

答案 1 :(得分:2)

使用awk

$ awk -F, 'NR==FNR{if($NF=="apple") a[$1]; next}
           $NF=="oranges" && ($1 in a){print $1}' ip.txt ip.txt
jon
tom
  • 处理输入两次
  • 在第一遍中,如果最后一个字段为apple-F,,设置为输入字段分隔符),则为数组添加键
  • 在第二次传递中,检查最后一个字段是否为oranges,且第一个字段是否为数组a
  • 的键


仅打印匹配数量:

$ awk -F, 'NR==FNR{if($NF=="apple") a[$1]; next}
           $NF=="oranges" && ($1 in a){c++} END{print c}' ip.txt ip.txt
2


进一步阅读:idiomatic awk了解有关两个文件处理和awk惯用语的详细信息

答案 2 :(得分:1)

输入:

jon,1,2,apple
jon,1,2,oranges
jon,1,2,pineaaple
fred,1,2,apple
tom,1,2,apple
tom,1,2,oranges
mary,1,2,apple

命令:

sed -n "/apple\|oranges/p" inputfile | cut -d"," -f1 | uniq -d

将输出包含苹果和橙子的人员列表:

jon
tom

评论后编辑:对于输入文件,其中第1列没有排序行,并且每个人可以有两个或更多重复的水果,例如:

jon,1,2,apple   
fred,1,2,apple
fred,1,2,apple                                                                                                                                          
jon,1,2,oranges                                                          
jon,1,2,pineaaple                                                        
jon,1,2,oranges                                                          
tom,1,2,apple                                                            
mary,1,2,apple                                                           
tom,1,2,oranges  

此命令将起作用:

sed -n "/\(apple\|oranges\)$/ s/,.*,/,/p" inputfile | sort -u | cut -d, -f1 | uniq -d

答案 3 :(得分:1)

我做了一个工作,只使用了grep和comm命令。

grep "apple" file | cut -d"," -f1 | sort > file1
grep "orange" file | cut -d"," -f1 | sort > file2
comm -12 file1 file2 > names.having.both.apple&orange 

comm -12仅显示2个文件之间的通用名称。

Jonathan的解决方案也奏效了。