一意の行を印刷する


15

との組み合わせ以外の一意の行を印刷するためのより良いソリューションはsortありuniqますか?


1
「より良い」とはどういう意味ですか?
ガベ。

@gabeたとえば、ファイル全体をメモリに保存する必要はありません。
Let_Me_Be

一部のバージョンsort(GNU coreutilsなど)は、入力が大きすぎてRAMに収まらない場合、一時ファイルと外部マージソートを使用します。また、他のほとんどのバージョンには-mオプションがあり、入力をsplitチャンク(たとえばwith )し、各チャンクをソートしてから、チャンクをマージすることで明示的に実行できます
jhnc

回答:


25

各同一行を任意の順序で1行だけ印刷するには:

sort -u

一意の行のみを任意の順序で印刷するには:

sort | uniq -u

各同一行を最初に出現した順序で1回だけ印刷するには、次のようにします(各行について、まだ表示されていない場合はその行を印刷し、その後、いずれの場合も表示されたカウンターをインクリメントします)

awk '!seen[$0] {print}
     {++seen[$0]}'

一意の行のみを最初の出現順に印刷するには:(の各行を記録seenlines、それが最初の出現の場合も入力します。入力の最後に、出現順に行のみを表示します一度)

awk '!seen[$0]++ {lines[i++]=$0}
     END {for (i in lines) if (seen[lines[i]]==1) print lines[i]}'

8
どうawk '!seen[$0]++ {print}'
asoundmove

10
またはさらに短いawk '!seen[$0]++'{print}は空のコマンドによって暗示されるためです。
-quazgar

3

一部の(ほとんどの?)バージョンには、パーツを直接実行sortする-uフラグがありuniqます。ただし、実装によっては行の長さが制限される場合がありますが、既にplainで制限されていますsort|uniq


1
え? sort -u少なくともV7に戻ります。
ギーコサウルス

ええと…SolarisまたはAIXにそれがないことを思い出したと思いました。私は間違っていますが、彼らは両方持っています。
マット

SolarisおよびAIXには-u、512文字の行長制限もあります。(実際には、Solaris 9 Sunのどこかで5120に引き上げられたと思います。しかし、GNUはまだ勝っています。)
geekosaur

@geekosaur:よろしいですか?ソートの行の長さの512バイト制限を削除するために行われた作業は、ベルシステムテクニカルのJP Lindermanによる「作業ソートルーチンの構築における理論と実践」に文書化されています。Journal、63、1827-1843(1984)。
ジョナサンレフラー

0

Perlはあなたに合っていますか?複製が隣接していない場合でも、元の順序で行を維持できます。Pythonまたはでコーディングすることもできますawk

while (<>) {
    print if $lines{$_}++ == 0;
}

これは短くすることができます

perl -ne 'print unless $lines{$_}++;'

与えられた入力ファイル:

abc
def
abc
ghi
abc
def
abc
ghi
jkl

出力は次のとおりです。

abc
def
ghi
jkl

$ linesはどこで定義されますか?
グレッグレベンタール14

そうではありません。そこではありませんので、use strict;またはuse warnings;(実際に、それはstrictここに最も関連性のあるもの)、使用についての苦情はありません%lines、それが定義される前に。制限付きで実行する場合my %lines;、ループの前に行が必要です。また、ハッシュは%lines; であることに注意してください。ハッシュの1つの要素は、$lines{$_}表記法を使用して参照されます。
ジョナサンレフラー14

sort大量のデータの場合、ソリューションの方が優れていると思います(OPは「メモリにファイル全体を保存する」ことを懸念していました)。sortデータが利用可能なメモリよりも大きい場合、コア外ソートを実行します。
クサラナナンダ

0

この質問への回答として、@ Gillesによる一意の行の印刷で言及した回答の最後の部分について、2つのハッシュを使用する必要性を排除しようとしました。

この解決策は次のとおりです:一意の行のみを最初に出現した順に印刷するには:

awk '{counter[$0]++} END {for (line in counter) if (counter[line]==1) print line}'

ここで、「counter」には、前に処理された行と同様の各行のカウントが格納されます。
最後に、カウンタ値が1である行のみを印刷します。

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