224

私はこのような.csvファイルを持っています:

stack2@example.com,2009-11-27 01:05:47.893000000,example.net,127.0.0.1
overflow@example.com,2009-11-27 00:58:29.793000000,example.net,255.255.255.0
overflow@example.com,2009-11-27 00:58:29.646465785,example.net,256.255.255.0
...

overflow@example.comファイル(つまり、上記の例に含まれている行の1つ)から重複する電子メール(行全体)を削除する必要があります。uniqフィールド1(コンマで区切る)のみで使用するにはどうすればよいですか?によるとmanuniq列のオプションはありません。

で何か試しましたsort | uniqが、うまくいきません。

4

8 に答える 8

377
sort -u -t, -k1,1 file
  • -uユニークな
  • -t,したがって、コンマは区切り文字です
  • -k1,1キーフィールド1の場合

テスト結果:

overflow@domain2.com,2009-11-27 00:58:29.793000000,xx3.net,255.255.255.0 
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1 
于 2009-12-16T16:14:50.927 に答える
122
awk -F"," '!_[$1]++' file
  • -Fフィールドセパレータを設定します。
  • $1最初のフィールドです。
  • _[val]valハッシュ_(通常の変数)で検索します。
  • ++インクリメントし、古い値を返します。
  • !論理否定を返します。
  • 最後に暗黙の印刷があります。
于 2009-12-16T17:17:05.757 に答える
19

複数の列を検討します。

列1と列3に基づいて、一意のリストを並べ替えて指定します。

sort -u -t : -k 1,1 -k 3,3 test.txt
  • -t :コロンは区切り文字です
  • -k 1,1 -k 3,3列1と列3に基づく
于 2014-01-21T01:30:06.550 に答える
8

または、uniqを使用する場合:

<mycvs.cvs tr -s ',' ' ' | awk '{print $3" "$2" "$1}' | uniq -c -f2

与える:

1 01:05:47.893000000 2009-11-27 tack2@domain.com
2 00:58:29.793000000 2009-11-27 overflow@domain2.com
1
于 2009-12-16T16:18:03.853 に答える
7

複製の最後の1つを保持したい場合は、使用できます

 tac a.csv | sort -u -t, -r -k1,1 |tac

これが私の要件でした

ここ

tacファイルを1行ずつ反転します

于 2015-12-14T13:46:26.720 に答える
1

これは非常に気の利いた方法です。

まず、一意性を比較する列が固定幅になるようにコンテンツをフォーマットします。これを行う1つの方法は、フィールド/列幅指定子( "%15s")でawkprintfを使用することです。

これで、uniqの-fおよび-wオプションを使用して、先行するフィールド/列をスキップし、比較幅(列幅)を指定できます。

これが3つの例です。

最初の例では...

1)対象の列を一時的にフィールドの最大幅以上の固定幅にします。

2)-f uniqオプションを使用して前の列をスキップし、-wuniqオプションを使用して幅をtmp_fixed_widthに制限します。

3)列から末尾のスペースを削除して、その幅を「復元」します(事前に末尾のスペースがなかったと仮定します)。

printf "%s" "$str" \
| awk '{ tmp_fixed_width=15; uniq_col=8; w=tmp_fixed_width-length($uniq_col); for (i=0;i<w;i++) { $uniq_col=$uniq_col" "}; printf "%s\n", $0 }' \
| uniq -f 7 -w 15 \
| awk '{ uniq_col=8; gsub(/ */, "", $uniq_col); printf "%s\n", $0 }'

2番目の例では...

新しいuniq列を作成する1.次に、uniqフィルターが適用された後でそれを削除します。

printf "%s" "$str" \
| awk '{ uniq_col_1=4; printf "%15s %s\n", uniq_col_1, $0 }' \
| uniq -f 0 -w 15 \
| awk '{ $1=""; gsub(/^ */, "", $0); printf "%s\n", $0 }'

3番目の例は2番目の例と同じですが、複数の列を対象としています。

printf "%s" "$str" \
| awk '{ uniq_col_1=4; uniq_col_2=8; printf "%5s %15s %s\n", uniq_col_1, uniq_col_2, $0 }' \
| uniq -f 0 -w 5 \
| uniq -f 1 -w 15 \
| awk '{ $1=$2=""; gsub(/^ */, "", $0); printf "%s\n", $0 }'
于 2017-04-25T01:22:31.513 に答える
-3

ええと、awkで列を分離するよりも簡単です。特定のファイルに対して特定の値を持つすべてのものを削除する必要がある場合は、grep-vを実行してみませんか。

たとえば、2番目の行の値が「col2」のすべてを削除するには:col1、col2、col3、col4

grep -v ',col2,' file > file_minus_offending_lines

これが十分でない場合は、一致する値が別の列に表示される可能性があるため、一部の行が不適切に削除される可能性があるため、次のように実行できます。

問題のある列を分離するためのawk:例:

awk -F, '{print $2 "|" $line}'

-Fは、区切り文字を「、」に設定します。$ 2は列2を意味し、その後にカスタム区切り文字が続き、行全体が続きます。次に、問題のある値で始まる行を削除してフィルタリングできます。

 awk -F, '{print $2 "|" $line}' | grep -v ^BAD_VALUE

次に、区切り文字の前にあるものを取り除きます。

awk -F, '{print $2 "|" $line}' | grep -v ^BAD_VALUE | sed 's/.*|//g'

(注-sedコマンドにはエスケープ値が含まれていないため、ずさんです。また、sedパターンは実際には「[^ |] +」(つまり、区切り文字以外のもの)のようにする必要があります。ただし、これで十分に明確であることが望まれます。

于 2009-12-16T16:13:10.023 に答える
-3

最初にファイルを並べ替えるsortことで、次に適用できますuniq

ファイルをうまくソートしているようです:

$ cat test.csv
overflow@domain2.com,2009-11-27 00:58:29.793000000,xx3.net,255.255.255.0
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
overflow@domain2.com,2009-11-27 00:58:29.646465785,2x3.net,256.255.255.0 
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack3@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack4@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1

$ sort test.csv
overflow@domain2.com,2009-11-27 00:58:29.646465785,2x3.net,256.255.255.0 
overflow@domain2.com,2009-11-27 00:58:29.793000000,xx3.net,255.255.255.0
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack3@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack4@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1

$ sort test.csv | uniq
overflow@domain2.com,2009-11-27 00:58:29.646465785,2x3.net,256.255.255.0 
overflow@domain2.com,2009-11-27 00:58:29.793000000,xx3.net,255.255.255.0
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack3@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack4@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1

また、AWKの魔法を使うこともできます。

$ awk -F, '{ lines[$1] = $0 } END { for (l in lines) print lines[l] }' test.csv
stack2@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack4@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
stack3@domain.com,2009-11-27 01:05:47.893000000,xx2.net,127.0.0.1
overflow@domain2.com,2009-11-27 00:58:29.646465785,2x3.net,256.255.255.0 
于 2009-12-16T16:14:37.647 に答える