次の入力:
A 13
A 12
B 17
C 33
D 344
C 24
A 5
C 99
列1が一意である行のみを取得したい:
B 17
D 344
awk
を使用した解決策はいいでしょうが、それ以外のものも受け入れられます。
awk
の場合:
awk 'NR==FNR { a[$1]++ } NR!=FNR && a[$1]==1' file file
(ファイル名は2回渡されます)。
編集:ファイルがstdin
からのものである場合は、一時的なコピーが必要です。このようなもの:
tmp="$( mktemp -t "${0##*/}"_"$$"_.XXXXXXXX )" && \
trap 'rm -f "$tmp"' 0 HUP INT QUIT TERM || exit 1
... | tee "$tmp" | awk '...' - "$tmp"
注文をスクランブルしてもかまわない場合は、
sort <file> | uniq -uw 1
見る man uniq
詳細については、ここに重要な部分があります。
-u, --unique
only print unique lines
-w, --check-chars=N
compare no more than N characters in lines
ご希望の場合awk
awk '
$1 in ARR{
ARR[$1] = RS;
next;
}
{
ARR[$1] = $0;
}
END{
for(i in ARR)
if(ARR[i] != RS)
print ARR[i];
}
' file
スクリプトは、1番目のフィールドをインデックスとして、1行を値として、配列ARRに行を入れました。配列に既に同じインデックスがある場合、値を"\ n"(改行)記号に変更します。ファイルが終了した後、値が"\ n"に等しくない配列の要素を出力します
デフォルトでは、awkのRS
変数はnewline
と等しいことに注意してください。
またはsedで実行できます
sort file |
sed '
:a;
$!N;
s/\(\S\+\s\).*\n\1.*/\1\a/;
ta;
/\a/P;
D;
'
$ cut -d' ' -f1 <file | sort | uniq -d | sed 's/^/^/' | grep -v -f /dev/stdin file
B 17
D 344
これはまず、列を切り取り、並べ替えてuniq -d
にフィードすることで、ファイルfile
の最初の列にある重複したエントリを取り出します(重複のみを報告します)。
次に、結果の各行の前に^
を付けて、行の先頭にアンカーされる正規表現を作成します。指定されたデータを含むsed
コマンドの出力は
^A
^C
最後のgrep
は、これらの正規表現を読み取り、それらのいずれにも一致しないすべての行をファイルから取り出します。 -f /dev/stdin
を使用して、grep
にsed
からパターンを読み取らせます。
結果は元のファイルと同じ順序になります。
Perl -lane '
exists $h{$F[0]} and undef $h{$F[0]},next;
( $h{$F[0]}, $h[@h] ) = ( $_, $F[0] );
END{ print $h{$_} for grep { defined $h{$_} } @h }
' yourfile
コードの操作は、最初のフィールドが以前に検出されたかどうかを確認し、その名前のキーがハッシュに存在するため、先に進み、この特定のキーの値をundef
がないため、とにかく最後に破棄される配列を構築するポイント。代わりに、より少ないメモリインプリントによって同じ情報を伝達します。
そして、最初のフィールドを初めて見るシナリオでは、ハッシュ%h
に現在の行を入力し、同時に配列@h
にこのキーを追加します。キーが検出された順序を保持するために、この手順を実行します。注文を気にしない場合は、このステップをなくすことができます。
最後に、すべての入力がダイジェストされたら、最後のEND
ブロックで、配列@h
の要素をループし、それらの要素から、ハッシュ%h
が定義した要素のみを取り出します値。 undef
の値は、2回以上見たことがあることを意味します。