uniq --uniqueが存在するほどuniqが一意でないのはどうしてですか?


35

pastebinからのランダムファイルのコマンドは次のとおりです。

wget -qO - http://pastebin.com/0cSPs9LR | wc -l
350
wget -qO - http://pastebin.com/0cSPs9LR | sort -u | wc -l
287
wget -qO - http://pastebin.com/0cSPs9LR | sort | uniq | wc -l
287
wget -qO - http://pastebin.com/0cSPs9LR | sort | uniq -u | wc -l
258

-uフラグが何をしているのかについてのマニュアルページは明確ではありません。何かアドバイス?


4
並べ替えを試す| uniq -d | wc -lを使用すると、違いを見つけることができます。:)
stoeff

回答:


42

短縮版:

  • uniq、なしで、出力の-uすべての行一意にします。
  • uniq -u入力からすべての一意の行のみを印刷します

少し長いバージョン:

uniqこれは、行が重複しているファイルを処理するためであり、それらの行が入力に連続して現れる場合のみです。したがって、その目的のために、一意の行はすぐに複製されない行です。

uniq短期記憶は非常に限られています。直前の行でない限り、入力の前に行が現れたかどうかを決して覚えません。これが、uniqとしばしばペアになっている理由ですsort。)

重複した行の実行に遭遇するとuniq-u引数なしで、その行のコピーを1つ出力します。(出力のすべての行を一意にします)。

-u引数、それが印刷さゼロ、その行のコピーを-重複のランは、単に出力から省略します。


1
ソートを必要としないオプションがあればいいのにと思います。ただし、ファイル全体をメモリに保持する必要があります(または、ソースが通常のファイルである場合は、ハッシュとオフセットを使用して大量のブックキーピングを行う)
Random832

3
@ Random832:そして、どの重複を保持するか(最初、最後、何か他のもの、構成可能)を決定する必要があり、その決定はアルゴリズムにグローバルに影響します。面倒。
スティーブジェソップ

1
@ Random832:入力する文字数とほぼ同じ場合は、のsort -u代わりに使用できますsort | uniq
オリバー

@oliverときどき、行の最初のインスタンスを再配置せずに保持する機能が必要であり、そのためのスクリプトを作成しました。
Random832

1
@hvd:のバージョンuniqが正規化と照合を行う場合、はい。ただし、それでもローカルな考慮事項です。ソートされた出力のどこに行が表示されるかを知っているので、いくつかの隣接する行のどれを保持するかを選択するだけです。入力がソートされていない場合、決定は単一化の操作全体に影響します。たとえば、最後の複製を保持する場合、入力の最後の行を読み取るまで何も出力できません...
スティーブジェソップ

53

uniqwith -uは、重複する行をスキップします。したがって:

$ printf "%s\n" 1 1 2 3 | uniq
1
2
3
$ printf "%s\n" 1 1 2 3 | uniq -u
2
3

通常、uniq行を最大1回印刷します(ソートされた入力を想定)。このオプションは、実際には一意の(再度表示されていない)行を実際に印刷します。


11
つまり、すべての個別の行を出力するのに対し、すべての個別の行を出力するため、uniqと呼ばれます。distinctuniq -u
スティーブジェソップ

一部のロケールでは、GNU で一意ではありませんuniq
cuonglm

私は受け入れ答えを何度も読んでいる必要がありますが、それはに沈むなかったあなたの例と段落を、それはそれは非常に明確にした後(と背中を行くと受け入れ答えを再読み込み、私もそれを得る):)。
マディバード

18

uniq POSIX仕様はそれを明確に説明しています。

-u
    Suppress the writing of lines that are repeated in the input.

-uオプションmake uniqは、繰り返される行を出力しません。

ほとんどのuniq実装はバイト比較を使用しましたが、GNU uniqは照合順序を使用して重複行をフィルタリングしました。そのため、一部のロケール、たとえばロケールで誤った結果が生成される可能性がありen_US.UTF-8ます。

$ printf '%b\n' '\U2460' '\U2461' | uniq
①

そして-uあなたにラインを与えませんでした:

$ printf '%b\n' '\U2460' '\U2461' | uniq -u
<blank>

そのためC、ロケールを設定してバイト比較を取得する必要があります。

$ printf '%b\n' '\U2460' '\U2461' | LC_ALL=C uniq
①
②

3
ここで間違っているのは、誤って①が②と同じようにソートされているロケールほどではないuniq(明らかにPOSIXの意図はstrcoll()比較の代わりにバイト比較を行うべきであったことであるsort -u)。少なくともGNU uniqはに準拠していsort -uます。
ステファンシャゼル

@StéphaneChazelas-仕様のどこでそれが明らかになったのですか?
mikeserv

uniqstrcoll関数とは対照的に、DO memcmp / strcmpのに必要な、私にとって非常に明白ではありませんが、そのことは、ジェフにしました。①と②を同じようにソートしているGNUロケールについては、同じようにソートする理由がないため、明らかにバグです。これはPOSIXで許可されていますが、いくつかの変更点があります。
ステファンシャゼル

8

通常:

echo "a b a b c c c" | tr ' ' '\n'
a
b
a
b
c
c
c

uniq:後続の2行は繰り返されません

echo "a b a b c c c" | tr ' ' '\n' | uniq
a
b
a
b
c

ソート済み

echo "a b a b c c c" | tr ' ' '\n' | sort
a
a
b
b
c
c
c

sort -u:2行の繰り返しはありません

echo "a b a b c c c" | tr ' ' '\n' | sort -u
a
b
c

sort / uniq:すべて個別

echo "a b a b c c c" | tr ' ' '\n' | sort | uniq
a
b
c

個別の発生をカウントします

echo "a b a b c c c" | tr ' ' '\n' | sort | uniq -c
2 a
2 b
3 c

繰り返されない行のみ(最初にソートされない)

echo "a b a b c c c" | tr ' ' '\n' | uniq -u
a
b
a
b

繰り返されない行のみ(ソート後)

echo "a b a b c c c Z" | tr ' ' '\n' | sort | uniq -u
Z

uniq -d:グループごとに1行ずつ、重複行のみを出力します

echo "a b a b c c c" | tr ' ' '\n' | uniq -d
c

..カウント

echo "a b a b c c c" | tr ' ' '\n' | uniq -dc
3 c

良い明確な例:)
マディバッド
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.