1. 概要

uniq コマンドは、重複した隣接する行を入力から削除するための便利なユーティリティであることがわかっています。

ただし、CSVファイルなどの列ベースの入力ファイルを処理する場合は、列が重複している行を削除したい場合があります。

uniq コマンドは、行全体が同じである場合にのみ行を削除するため、この場合は役に立ちません。

このチュートリアルでは、行全体ではなく列に対して「uniq」操作を実行する方法を学習します。

2. 問題の紹介

まず、例としてCSVファイルprice.csvを作成しましょう。

Product,Price,Update
Monitor,218,2019-01-01
Keybord,20,2019-02-02
Wireless Mouse,25,2019-02-02
Keybord,22,2019-03-02
Wireless Mouse,30,2019-03-02
Keybord,18,2019-04-02
Monitor,208,2019-02-01
Keybord,25,2019-05-02
Monitor,230,2019-03-01

price.csv ファイルには、3つの列があり、各行には、各製品の価格が更新されたときが記録されます。

製品が重複している行を削除したいと思います。

したがって、product列で「uniq」操作を行います。

問題を解決する2つの方法を見て、2つのアプローチを比較してみましょう。sortawk。

3. sortを使用する

sort コマンドは、特定のフィールドで行をソートし、ソート結果から重複を削除できます。 重複の場合、最初のインスタンスのみが保持されます。

このセクションでは、sortコマンドを使用して問題を解決します。

price.csv ファイルでは、最初の行がヘッダー行であり、データを並べ替えるときにヘッダーを並べ替えに参加させたくないことがわかります。

これを行うには、 tail コマンドを使用して最初の行を切り取り、残りをsortコマンドにパイプします。

$ tail -n+2 price.csv | sort -u -t, -k1,1                        
Keybord,20,2019-02-02
Monitor,218,2019-01-01
Wireless Mouse,25,2019-02-02

上記のコマンドを詳しく見て、その各部分を理解しましょう。

  • tail -n + 2 :2行目からファイルの終わりまで取得します
  • sort -u :重複を並べ替えて削除します
  • -t、:フィールド区切り文字としてコンマを定義します
  • -k1,1 :最初の列で並べ替え

おそらく、出力にヘッダー行を残したいのです。

これを実現するには、 headコマンドで最初の行を最初に出力してから、上記のコマンドを実行します。

$ head -n1 price.csv && tail -n+2 price.csv | sort -u -t, -k1,1 
Product,Price,Update
Keybord,20,2019-02-02
Monitor,218,2019-01-01
Wireless Mouse,25,2019-02-02

4. awkを使用する

awk は、*nixシステムの非常に強力なコマンドラインテキスト処理ツールです。

この問題に簡潔に対処できます。

$ awk -F, 'NR==1 || !a[$1]++' price.csv 
Product,Price,Update
Monitor,218,2019-01-01
Keybord,20,2019-02-02
Wireless Mouse,25,2019-02-02

sort コマンドを使用したソリューションと比較すると、awkコマンドははるかにコンパクトです。 よく見てみましょう。

-F、は、フィールド区切り文字としてコンマを設定します。

NR == 1 式はヘッダー行を処理します:awkは出力の最初の行を出力します。

ここで注意が必要な部分があります。!a [$ 1] ++、それがどのように機能するかを理解しましょう。

まず、awkでは、ゼロ以外の数値 patterntrue、と評価され、trueパターンはデフォルトのアクションをトリガーします[ X156X]:印刷falseパターンは何もしません。

例に戻ります。

  • Keyboard」の行が初めてawkに来ると、 awk連想配列要素を作成します: a [ 「キーボード」]デフォルト値: 0
  • a [“ Keyboard”] ++ は元の値を返し、その値を1ずつインクリメントするため、式は 0 を返し、 a [“ Keyboard”]が得られます。 = 1
  • !a [“ Keyboard”] ++ !0 になります。これまでに学んだように、 trueと評価され、がデフォルトのアクションをトリガーします。 :現在の行を印刷します
  • Keyboard」の行が再び来ると、配列要素はすでに存在し、 a [“Keyboard”]++は1を返し、2を保持します
  • !a [“ Keyboard”] ++ 今回は!1 になるため、 false :何もしません。

このように、最初の「 Keyboard 」が印刷された後、配列要素 a [“ Keyboard”]は正の数を保持します。 次のすべての行に「 キーボード ” 作る予定です !a[「キーボード」]++ 次のように評価します間違い。 したがって、重複は削除されます。

5. awk対。 ソート

これまで、この問題を解決するための2つの異なるアプローチを見てきました。 それらの出力を比較すると、それらが異なることがわかります:

$ diff -y <(head -n1 price.csv && tail -n+2 price.csv | sort -u -t, -k1,1) <(awk -F, 'NR==1 || !a[$1]++' price.csv)
Product,Price,Update				 Product,Price,Update
Keybord,20,2019-02-02			<
Monitor,218,2019-01-01				 Monitor,218,2019-01-01
				            	>	Keybord,20,2019-02-02
Wireless Mouse,25,2019-02-02		 Wireless Mouse,25,2019-02-02

これは、 sortコマンドが最初にキー列で行をソートするためです。これにより、行の元の順序が変更される可能性がありますが、awkは変更されません。

2つのソリューションを確認して比較してみましょう。

  • 入力にヘッダー行がある場合、awksortアプローチよりもはるかに簡単にヘッダー行を処理できます。
  • awk は単一のプロセスで問題を解決しますが、 sort アプローチには、 head tail、sort[の3つのプロセスが必要です。 X152X]
  • awk は、 awk ソリューションがファイルをソートしないため、sortアプローチよりも高速です。
  • ソートされた結果が必要な場合は、sortアプローチが正しい選択です。

6. 結論

この記事では、最初に列問題による「uniq」を紹介しました。 次に、sortユーティリティとawkコマンドを使用してそれを解決する方法を学びました。

最後に、2つのアプローチを比較して、さまざまな要件に応じて適切なアプローチを選択する方法を理解しました。