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

Bash awk或shell命令,根据第4列中的值计算第1列中值的出现次数,bash,shell,unix,awk,sed,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文件=>2(jon和tom)用于输入: jon,1,2,apple jon,1,2,oranges jon,1,2,pi

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

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文件=>2(jon和tom)

用于输入:

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
对于输入:

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

使用
awk
非常简单:

awk -F, \
    '$4 == "apple"   { apple[$1]++  }
     $4 == "oranges" { orange[$1]++ }
     END { for (name in apple) if (orange[name]) print name }' 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
条目,如果有,就会打印出来

如a中所述,它可以使用
中的

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
第一个答案也可以在
END
循环中使用
in


请注意,所有这些解决方案都可以嵌入到一个脚本中,该脚本将接受来自标准输入(管道或重定向文件)的数据—它们不需要读取输入文件两次。如果给定了文件名,您可以将
数据
替换为
“$@”
,如果没有指定文件名,您可以将其替换为标准输入。如果可能,这种灵活性值得保留。

使用
awk
非常简单:

awk -F, \
    '$4 == "apple"   { apple[$1]++  }
     $4 == "oranges" { orange[$1]++ }
     END { for (name in apple) if (orange[name]) print name }' 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
条目,如果有,就会打印出来

如a中所述,它可以使用
中的

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
第一个答案也可以在
END
循环中使用
in

请注意,所有这些解决方案都可以嵌入到一个脚本中,该脚本将接受来自标准输入(管道或重定向文件)的数据—它们不需要读取输入文件两次。如果给定了文件名,您可以将
数据
替换为
“$@”
,如果没有指定文件名,您可以将其替换为标准输入。如果可能,这种灵活性值得保留。

使用
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

进一步阅读:有关两种文件处理和awk习惯用法的详细信息,请参见
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


进一步阅读:关于两个文件处理和awk习惯用法的详细信息,我做了一个变通,只使用了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仅显示两个文件之间的通用名称


Jonathan的解决方案也很有效。

我做了一个变通,只使用了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仅显示两个文件之间的通用名称


Jonathan的解决方案也有效。

请添加您尝试过的代码,并解释您面临的问题it@Sundeep,我对unix还很陌生,所以我不知道该怎么做,也不知道是否有可能。没问题,我也曾经是个新手。。我建议你去看看(awk更适合这个imo),自己尝试一下,然后在你遇到代码问题时问一下。。。你也看到了,我正在看文件。。我找到了一个办法。。grep“apple”file | cut-d“,“-f1 | sort>file1,然后grep“oranges”file | cut-d“,“-f1 | sort>file2,然后comm-12 file1 file2。。。请将代码和解释添加到问题:)或作为答案…请添加您尝试过的代码并解释您面临的问题it@Sundeep,我对unix还很陌生,所以我不知道该怎么做,也不知道是否有可能。没问题,我也曾经是个新手。。我建议你去看看(awk更适合这个imo),自己尝试一下,然后在你遇到代码问题时问一下。。。你也看到了,我正在看文件。。我找到了一个办法。。grep“apple”file | cut-d“,“-f1 | sort>file1,然后grep“oranges”file | cut-d“,“-f1 | sort>file2,然后comm-12 file1 file2。。。请添加该代码并解释