获取bash列中唯一值的计数


95

我有几列的制表符分隔文件。我想计算一个文件夹中所有文件在一列中出现不同值的频率,并按照计数从高到低的顺序进行排序(从最高计数开始)。我将如何在Linux命令行环境中完成此任务?

它可以使用任何常见的命令行语言,例如awk,perl,python等。

Answers:


152

要查看第二列的频率计数(例如):

awk -F '\t' '{print $2}' * | sort | uniq -c | sort -nr

fileA.txt

z    z    a
a    b    c
w    d    e

fileB.txt

t    r    e
z    d    a
a    g    c

fileC.txt

z    r    a
v    d    c
a    m    c

结果:

  3 d
  2 r
  1 z
  1 m
  1 g
  1 b

68

这是在外壳中执行此操作的方法:

FIELD=2
cut -f $FIELD * | sort| uniq -c |sort -nr

bash最擅长的就是这种事情。


22
事物的“排序” ... ar ar ar!:)
约翰·里克斯

3
Kinda sorta独特的东西。:P(顺便用-d,逗号或其他分隔符来分隔字段)。
cprn

4
我用过cut -f 1 -d ' '。非常感谢。:)
阿方索西川

8

GNU网站表明这个漂亮的awk脚本,它打印两个单词和它们的频率。

可能的变化:

  • 您可以通过管道传递sort -nr(并反向wordfreq[word])以降序查看结果。
  • 如果需要特定的列,则可以省略for循环,只需编写freq[3]++-用列号替换3。

开始:

 # wordfreq.awk --- print list of word frequencies

 {
     $0 = tolower($0)    # remove case distinctions
     # remove punctuation
     gsub(/[^[:alnum:]_[:blank:]]/, "", $0)
     for (i = 1; i <= NF; i++)
         freq[$i]++
 }

 END {
     for (word in freq)
         printf "%s\t%d\n", word, freq[word]
 }

2
很棒的示例脚本。它充分展示了awk的功能。
大卫·曼

这个脚本对我确定我确实需要注意的Excel工作簿中的哪些行很有帮助:)(将Excel内容复制到文本文件,使用awk,瞧!我可以为grep -n创建一个模式文件) 。
Jubbles

6

佩尔

这段代码计算所有列的出现,并为它们中的每一个打印一个排序的报告:

# columnvalues.pl
while (<>) {
    @Fields = split /\s+/;
    for $i ( 0 .. $#Fields ) {
        $result[$i]{$Fields[$i]}++
    };
}
for $j ( 0 .. $#result ) {
    print "column $j:\n";
    @values = keys %{$result[$j]};
    @sorted = sort { $result[$j]{$b} <=> $result[$j]{$a}  ||  $a cmp $b } @values;
    for $k ( @sorted ) {
        print " $k $result[$j]{$k}\n"
    }
}

将文本另存为columnvalues.pl
perl columnvalues.pl files*

说明

在顶级的while循环中:
*循环合并输入文件的每一行
*将行拆分为@Fields数组
*对于每一列,请增加结果哈希数组数据结构

在顶层for循环中:
*在结果数组上循环
*打印列号
*获取该列中使用的值
*按出现的次数对值进行
排序*基于值的二级排序(例如b vs g vs m vs z)
*使用排序后的列表遍历结果哈希
*打印每次出现的值和编号

结果基于@Dennis提供的样本输入文件

column 0:
 a 3
 z 3
 t 1
 v 1
 w 1
column 1:
 d 3
 r 2
 b 1
 g 1
 m 1
 z 1
column 2:
 c 4
 a 3
 e 2

.csv输入

如果您的输入文件是.csv,请更改/\s+//,/

混淆

在一个丑陋的比赛中,Perl装备精良。
这种单线执行相同的操作:

perl -lane 'for $i (0..$#F){$g[$i]{$F[$i]}++};END{for $j (0..$#g){print "$j:";for $k (sort{$g[$j]{$b}<=>$g[$j]{$a}||$a cmp $b} keys %{$g[$j]}){print " $k $g[$j]{$k}"}}}' files*

2

红宝石(1.9+)

#!/usr/bin/env ruby
Dir["*"].each do |file|
    h=Hash.new(0)
    open(file).each do |row|
        row.chomp.split("\t").each do |w|
            h[ w ] += 1
        end
    end
    h.sort{|a,b| b[1]<=>a[1] }.each{|x,y| print "#{x}:#{y}\n" }
end

5
这是非常有趣的,不仅因为我使用了它而且它起作用了,还因为我对红宝石的丑陋程度感到惊讶。我认为perl不好!
ryansstack 2014年

在红宝石的辩护中,这可以真正消除。例如,使用each_with_object等等。简而言之,这写得有些粗略。
Rambatino
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.