web-dev-qa-db-ja.com

異なるファイルの最初の列を比較する

あるファイルを同じディレクトリ内の他のファイルと比較したい。

file1.txt含まれています:

move 34#123#    
get 11#278    
put 33#29#567#23

file1.txtファイルと比較する必要があります1.txtおよび2.txt

1.txt含まれています:

move 11    
put 34    
run 13

2.txt含まれています:

get 14    
move 66

次のような結果が必要です。

move 2    
get 1    
put 1

どうすればこれを達成できますか?

1
Rincy Raphael

これがawkソリューションです。

$ awk 'FNR==NR{a[$1];next}($1 in a){++a[$1]}
    END{for(i in a){print i" "a[i]}}' file1.txt 1.txt 2.txt
put 1
get 1
move 2

説明

  • FNR==NR{a[$1];next}file1.txtを処理するときに、連想配列a$1の発生をマークします。
  • ($1 in a){++a[$1]}1.txt2.txtを処理するときに、$1が連想配列aに存在するかどうかを確認し、存在する場合は、カウントを1増やします。
  • 最後に、連想配列aをループし、キー(ファイルの最初のフィールド)とその値(1.txt2.txtの出現回数)を出力します。

Perlの別の解決策は、同じロジックです。

$ Perl -alne '++$i;                  
    if ($. == $i) {
        $h{$F[0]}=0;
        close ARGV if eof;
        next;
    }
    ++$h{$F[0]} if defined $h{$F[0]};
END {
    for (keys %h) {
        print $_." ".$h{$_};
    }
}' file1.txt 1.txt 2.txt
move 2
get 1
put 1
4
cuonglm

さまざまなツール、grepawksort、およびuniqを使用する代替ツールを示しています。確かに、より多くのツールを使用しますが、AWKと比較して何が起こっているのかを理解する方が簡単だと思います。

$ for i in 1.txt 2.txt; do grep -f <(awk '{print $1}' $i) file1.txt; done | \
    awk '{print $1}' | sort | uniq -c

$ for i in 1.txt 2.txt; do grep -f <(awk '{print $1}' $i) file1.txt; done | \
    awk '{print $1}' | sort | uniq -c
      1 get
      2 move
      1 put

使い方

これが少し展開された例です。

$ for i in 1.txt 2.txt; do 
    grep -f <(awk '{print $1}' $i) file1.txt
  done | \
    awk '{print $1}' | sort | uniq -c

forループは、照合対象の2つのファイル1.txt2.txtを通過します。ループを通過するたびに、これらのファイルの1つからの最初の列を静的な文字列のセットとして使用してgrepにターゲットファイルfile1.txtでこれらを探します。これはそれを行う行です:

$ grep -f <(awk '{print $1}' $i) file1.txt

forループの各ファイルを使用して実行した後、すべての出力を取得し、その最初の列のみを選択します。

move
put
move
get

次に、sortuniqを使用して、見た各タイプの数を集計します。

1
slm

joinを使用した別の方法は次のとおりです。

join -1 1 -2 2 -o 0 2.1 <(sort -k1,1 file1.txt) <(cut -d ' ' -f1 1.txt 2.txt | sort | uniq -c)

出力がソートされることに注意してください。

get 1
move 2
put 1

file1.txtからの順序を保持したい場合(例:.

move 2
get 1
put 1

あなたが実行できる:

join -j2 -o 1.1 0 2.1 <(nl -ba -nrz file1.txt | sort -k2,2) \
<(cut -d ' ' -f1 1.txt 2.txt | sort | uniq -c) | sort -k1 | cut -d ' ' -f2-
0
don_crissti