Bash'de bir sütundaki benzersiz değerlerin sayısını alma


98

Birkaç sütun içeren sekmeyle ayrılmış dosyalarım var. Bir klasördeki tüm dosyalar için bir sütundaki farklı değerlerin ortaya çıkma sıklığını saymak ve bunları azalan sırayla sıralamak istiyorum (önce en yüksek sayı). Bunu bir Linux komut satırı ortamında nasıl başarabilirim?

Awk, perl, python vb. Gibi yaygın herhangi bir komut satırı dilini kullanabilir.

Yanıtlar:


156

İkinci sütun için sıklık sayısını görmek için (örneğin):

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

Sonuç:

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

69

İşte bunu kabukta yapmanın bir yolu:

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

Bu, Bash'in harika olduğu türden bir şey.


23
"Bir çeşit" şey ... ar ar! :)
John Rix

3
Bir tür benzersiz bir şey. : P (btw. -d,Alanları virgül veya başka bir sınırlayıcıyla sınırlandırmak için kullanın).
cprn

4
Kullandım cut -f 1 -d ' '. Çok teşekkür ederim. :)
Alfonso Nishikawa

8

GNU sitesi kelimeleri ve onların frekansını hem yazdırır bu güzel awk komut öneriyor.

Olası değişiklikler:

  • Sonucu azalan sırada görmek için dikey çizgi yapabilirsiniz sort -nr(ve ters wordve freq[word]).
  • Belirli bir sütun istiyorsanız, for döngüsünü atlayabilir ve basitçe yazabilirsiniz freq[3]++- 3'ü sütun numarasıyla değiştirin.

İşte:

 # 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
Harika örnek komut dosyası. Awk'nin yeteneklerinin çoğunu gösterir.
David Mann

Bu komut dosyası, bir Excel çalışma kitabındaki hangi satırlara gerçekten dikkat etmem gerektiğini belirlemem için bana yardımcı oldu :) (Excel içeriğini metin dosyasına kopyaladı, awk kullanın ve işte! Grep -n için bir kalıp dosyası oluşturabilirim) .
Jubbles

6

Perl

Bu kod, tüm sütunların oluşumlarını hesaplar ve her biri için sıralı bir rapor yazdırır:

# 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"
    }
}

Metni columnvalues.pl olarak kaydedin.
Çalıştırın: perl columnvalues.pl files*

Açıklama

En üst seviye while döngüsünde:
* Birleşik giriş dosyalarının her satırı üzerinde döngü yapın *
Satırı @Fields dizisine bölün
* Her sütun için sonuç dizi-hash veri yapısını artırın

En üst düzey döngüde:
* Sonuç dizisi üzerinde döngü *
Sütun numarasını yazdır
* Bu sütunda kullanılan değerleri alın
* Değerleri tekrar sayısına göre
sıralayın * Değere göre ikincil sıralama (örneğin m vs z)
* Sıralanmış listeyi kullanarak sonuç karmasını yineleyin
* Her bir oluşumun değerini ve sayısını yazdırın

@Dennis tarafından sağlanan örnek girdi dosyalarına dayalı sonuçlar

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 girişi

Giriş dosyalarınız .csv ise, şu şekilde değiştirin /\s+/:/,/

Gizleme

Çirkin bir yarışmada Perl, özellikle iyi donanımlıdır.
Bu tek astar aynı şeyi yapar:

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

Ruby (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
Bu çok ilginç, hem onu ​​kullandım ve işe yaradı, hem de yakutun ne kadar çirkin olduğuna şaşırdım. Perl'in kötü olduğunu düşündüm!
ryansstack

Ruby'nin savunmasında, bu gerçekten düzeltilebilir. Örneğin, each_with_objectdiğer şeylerin yanı sıra kullanmak . Kısacası, bu biraz kabaca yazılmış.
Rambatino
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.