あるファイルを同じディレクトリ内の他のファイルと比較したい。
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
どうすればこれを達成できますか?
これが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.txt
と2.txt
を処理するときに、$1
が連想配列a
に存在するかどうかを確認し、存在する場合は、カウントを1増やします。a
をループし、キー(ファイルの最初のフィールド)とその値(1.txt
と2.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
さまざまなツール、grep
、awk
、sort
、および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.txt
と2.txt
を通過します。ループを通過するたびに、これらのファイルの1つからの最初の列を静的な文字列のセットとして使用してgrep
にターゲットファイルfile1.txt
でこれらを探します。これはそれを行う行です:
$ grep -f <(awk '{print $1}' $i) file1.txt
for
ループの各ファイルを使用して実行した後、すべての出力を取得し、その最初の列のみを選択します。
move
put
move
get
次に、sort
とuniq
を使用して、見た各タイプの数を集計します。
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-