1. 概要

Linuxコマンドラインを使用する場合、テキストファイルの処理は一般的な操作です。 場合によっては、重複した行を含むテキストファイルが発生することがあります。 このチュートリアルでは、テキストファイルの繰り返し行をカウントする方法を学習します。

2. 問題の紹介

重複行をカウントする方法を簡単に説明するために、サンプルテキストファイルinput.txtを作成しましょう。

$ cat input.txt
I will choose MAC OS.
I will choose Linux.
I will choose MAC OS.
I will choose Linux.
I will choose MAC OS.
I will choose Linux.
I will choose Linux.
I will choose Microsoft Windows.
I will choose Linux.
I will choose Linux.

上記の出力が示すように、input.txtには重複した行が含まれています。 次に、各行の出現回数をカウントします。

このチュートリアルでは、問題を解決するための2つのアプローチについて説明します。

  • sortコマンドとuniqコマンドを併用する
  • awkコマンドの使用

その後、2つのアプローチを比較し、どちらが問題のより良い解決策になるかについて説明します。

3. sortコマンドとuniqコマンドの組み合わせ

uniqコマンドには、入力ファイル内の出現回数をカウントするための便利な-cオプションがあります。 これはまさに私たちが探しているものです。

ただし、注意しなければならないことの1つは、 -cオプションを指定したuniqコマンドは、重複した行が隣接している場合にのみ機能することです。 つまり、最初に繰り返し行をグループ化する必要があります。 sort コマンドは、それを手に入れることができます。

最初にinput.txtをソートし、結果を-cオプションを指定してuniqにパイプします。

$ sort input.txt | uniq -c
      6 I will choose Linux.
      3 I will choose MAC OS.
      1 I will choose Microsoft Windows.

出力が示すように、各行の出現回数が行と一緒に出力されます。 問題は解決された。

4. awkコマンドの使用

または、非常に単純なawkワンライナーを使用してこの問題を解決することもできます。

$ awk '{ a[$0]++ } END{ for(x in a) print a[x], x }' input.txt 
1 I will choose Microsoft Windows.
6 I will choose Linux.
3 I will choose MAC OS.

上記の出力から、awkワンライナーでも問題が解決したことがわかります。

ここで、awkコードがどのように機能するかを理解しましょう。

  • {a [$ 0] ++} 連想配列 a [KEY] )を作成して、行と出現回数を記録しました。 KEY は入力ファイルの行であり、値 a[KEY]KEYの出現回数です。
  • END {for(x in a)print a [x]、x} :すべての行を処理した後、ENDブロックを使用して配列内のすべての要素を出力しました

5. 2つのソリューションの比較

sortおよびuniqコマンドを使用したソリューションは便利です。 同様に、awkソリューションも非常に簡単です。 質問したい場合がありますが、どちらがより良い解決策ですか?

このセクションでは、パフォーマンス、柔軟性、および拡張性の観点から2つのソリューションを比較してみましょう。

5.1. より大きな入力ファイルの作成

input.txt には10行しかないため、どちらのアプローチでも問題の解決は非常に高速です。

2つのソリューションのパフォーマンスをよりよく比較するために、単純なシェルスクリプトcreate_input.shを使用してより大きな入力ファイルを生成します。

#!/bin/sh

# the output file
BIG_FILE="big_input.txt"
# total number of lines
TOTAL=1000000
# an array to store lines
ARRAY=(
    "I will choose Linux."
    "I will choose Microsoft Windows."
    "I will choose MAC OS."
    )

# remove the file
rm -f "$BIG_FILE"

while (( TOTAL > 0 )) ; do
    echo ${ARRAY[$(( $RANDOM % 3 ))]} >> $BIG_FILE
    (( TOTAL-- ))
done

上記のスクリプトでは、ARRAYという名前のBash配列に3行を保存しています。 次に、 while ループで、配列からランダムに1行を選択し、big_input.txtというファイルに書き込みます。

スクリプトを実行すると、100万行のファイルが得られます。

$ wc -l big_input.txt 
1000000 big_input.txt

次に、このファイルを入力として使用して、2つのソリューションのパフォーマンスを比較します。

5.2. パフォーマンス

time コマンドを使用して実行時間を測定し、各ソリューションをこの大きな入力ファイルに適用してみましょう。

まず、ソートをテストしましょう| uniq コマンド:

$ time (sort big_input.txt | uniq -c)
 333814 I will choose Linux.
 333577 I will choose MAC OS.
 332609 I will choose Microsoft Windows.

real	0m0.766s
user	0m1.995s
sys	0m0.053s

次に、awkコマンドをテストします。

$ time awk '{a[$0]++}END{for(x in a)print a[x], x}' big_input.txt
333814 I will choose Linux.
333577 I will choose MAC OS.
332609 I will choose Microsoft Windows.

real	0m0.190s
user	0m0.182s
sys	0m0.001s

上記のテスト結果は、awkコマンドがsort|よりもはるかに高速(このマシンでは約4倍高速)であることを明確に示しています。 uniqの組み合わせ。 それの訳は:

  • awk コマンドは単一のプロセスのみを開始しますが、 sort | uniqアプローチには2つのプロセスが必要です
  • awk コマンドはファイルを1回だけ処理しますが、 sort | uniq の組み合わせは、入力ファイルのすべての行を2回処理する必要があります
  • sort コマンドは、ファイルをさらにソートします。 したがって、複雑さは awkコマンドよりも高くなります。O(nLog(n))> O(n)

5.3. 柔軟性と拡張性

uniq-cコマンドは便利です。 ただし、出力の形式は固定されています。 出力を調整したい場合は、他のテキスト処理ユーティリティを使用する必要があります。 さらに、これによりプロセスが追加され、出力の処理回数が増えます。

反対側では、 awkコマンドを使用して、出力の形式を自由に制御できます。

たとえば、各行の後にカウントを入れましょう。

$ awk '{ a[$0]++ } END{ for(x in a) printf "%s [ count: %d ]\n", x, a[x] }' input.txt
I will choose Microsoft Windows. [ count: 1 ]
I will choose Linux. [ count: 6 ]
I will choose MAC OS. [ count: 3 ]

さらに、強力な awk 言語のおかげで、 awkコマンドを簡単に拡張して、より複雑な要件を処理できます。

たとえば、3回以上重複している行のみを出力する場合は次のようになります。

$ awk '{ a[$0]++ } END{ for(x in a) if(a[x]>3) print a[x], x }' input.txt 
6 I will choose Linux.

または、より詳細なレポートを取得したい場合:

$ awk '{ a[$0]++ } END{ for(x in a) printf "%.2f%% (%d in %d): %s\n",100*a[x]/NR,a[x],NR, x }' input.txt
10.00% (1 in 10): I will choose Microsoft Windows.
60.00% (6 in 10): I will choose Linux.
30.00% (3 in 10): I will choose MAC OS.

6. 結論

この記事では、テキストファイル内の重複行をカウントする2つの異なる方法を学びました。 その後、パフォーマンス、柔軟性、および拡張性の観点から2つのソリューションを比較しました。

ソート| uniqの組み合わせは簡単です。 ただし、特に大きなファイルを処理する必要がある場合は、awkソリューションの方が適しています。