열별로 '유니크'하는 방법이 있습니까?


195

다음과 같은 .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위 예에 포함 된 행 중 하나 ). uniq필드 1 (쉼표로 구분)에서만 사용하려면 어떻게합니까 ? 에 따르면 man, uniq열에 대한 옵션이 없습니다.

나는 무언가를 시도했지만 sort | uniq작동하지 않습니다.

답변:


327
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 

3
열에 쉼표 자체가 포함 된 경우 작동하지 않습니다 (따옴표 포함)
user775187

13
왜 -k1,1에서, 1이 필요합니까? 왜 -k1이 아닌가?
hello_there_andy

18
@hello_there_andy : 설명서 ( man sort)에 설명되어 있습니다 . 시작 및 중지 위치를 나타냅니다.
Serrano

3
@CarlSmotricz : 나는 그것을 테스트하고 그것을 어떻게 확인 sort"의 맨 페이지는 말한다 -u, --unique-c, 엄격한 순서에 대한 검사,없이 -c, 동일한 실행의 첫 번째 출력 ." 따라서 실제로는 "정렬하기 전에 첫 번째 중복 항목"입니다.
Geremia

2
이것은 줄의 순서도 바꾸지 않습니까?
rkachach

104
awk -F"," '!_[$1]++' file
  • -F 필드 구분 기호를 설정합니다.
  • $1 첫 번째 필드입니다.
  • _[val]val해시 _(일반 변수)를 찾습니다 .
  • ++ 증분하고 이전 값을 반환합니다.
  • ! 논리를 반환하지 않습니다.
  • 끝에 암시 적 인쇄가 있습니다.

4
이 접근 방식은 정렬보다 2 배 빠릅니다.
bitek

9
이것은 또한 원래 순서대로 라인을 유지하는 추가 이점이 있습니다!
AffluentOwl

8
첫 번째 대신 마지막 uniq 이 필요한 경우이 awk 스크립트가 도움이됩니다.awk -F',' '{ x[$1]=$0 } END { for (i in x) print x[i] }' file
Sukima

4
@eshwar은 사전 색인에 더 많은 필드를 추가합니다! 예를 들어 !_[$1][$2]++처음 두 필드를 기준으로 정렬하는 데 사용할 수 있습니다. 내 awk-fu하지만, 필드의 범위에서 고유 할 수 있도록 강력한 충분하지 않습니다. :(
Soham Chowdhury

1
훌륭한! 이 옵션은 줄 순서를 유지하기 때문에 답보다 낫습니다
rkachach

16

여러 열을 고려합니다.

열 1과 열 3을 기준으로 고유 한 목록을 정렬하고 제공하십시오.

sort -u -t : -k 1,1 -k 3,3 test.txt
  • -t : 콜론은 구분자입니다
  • -k 1,1 -k 3,3 열 1과 열 3을 기준으로

8

또는 uiq를 사용하려는 경우 :

<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

5
가능한 단순화를 지적하고 싶습니다 : cat! tr로 파이핑하는 대신 tr을 사용하여 파일을 읽도록하십시오 <. 파이핑 스루 cat는 초보자가 일반적으로 사용하는 불필요한 합병증입니다. 많은 양의 데이터에는 성능에 영향을 미칩니다.
Carl Smotricz 2009

4
알아 둘만 한. 고마워! (물론 이것은 "고양이"와 "게으름"에 대한 생각입니다.)
Carsten C.

를 사용하면 필드 반전을 단순화 할 수 있습니다 rev.
Hielke Walinga

5

복제본 중 마지막 사본을 유지하려면 사용할 수 있습니다.

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

내 요구 사항은 어느 것입니까

여기

tac 파일을 한 줄씩 뒤집습니다.


1

여기 아주 좋은 방법이 있습니다.

먼저 고유성을 비교할 열이 고정 너비가되도록 내용의 형식을 지정하십시오. 이를 수행하는 한 가지 방법은 필드 / 열 너비 지정자 ( "% 15s")와 함께 awk printf를 사용하는 것입니다.

이제 uniq의 -f 및 -w 옵션을 사용하여 선행 필드 / 열을 건너 뛰고 비교 너비 (열 너비)를 지정할 수 있습니다.

다음은 세 가지 예입니다.

첫 번째 예에서 ...

1) 관심있는 열을 필드의 최대 너비보다 크거나 같은 고정 너비로 ​​임시 설정하십시오.

2) -f uniq 옵션을 사용하여 이전 열을 건너 뛰고 -w uniq 옵션을 사용하여 너비를 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 }'

두 번째 예에서 ...

새 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 }'

세 번째 예는 두 번째 예와 동일하지만 여러 열에 적용됩니다.

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 }'

-3

주어진 파일에 대해 특정 값을 가진 모든 것을 제거 해야하는 경우 grep -v를 수행하지 않는 이유는 무엇입니까?

예 : 두 번째 줄에서 "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 명령이 느슨합니다. 또한 sed 패턴은 실제로 "[^ |] +"(예 : 구분 기호가 아닌 것)와 같아야합니다. 그러나 이것은 충분히 명확합니다.


3
그는 행을 제거하지 않고 특정 문자열이있는 단일 행의 사본을 유지하려고합니다. Uniq가 올바른 사용 사례입니다.
ingyhere

-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 

질문에서 요구 한대로 별로 고유하지 않습니다 . 이것은 전체 라인에 고유합니다. 또한, 당신은 uniq을 수행하기 위해 정렬 할 필요가 없습니다. 둘은 상호 배타적입니다.
Javid Jamae

1
네, 맞아요. 마지막 예는 허용 된 답변이 훨씬 깨끗하지만 질문에 대한 내용을 수행합니다. 에 관해서는 sort, 다음 uniq, sort하기 전에 수행해야 할 uniq이 작동하지 않습니다, 그렇지 않으면 (하지만 당신은 두 번째 명령 그냥 사용을 건너 뛸 수 있습니다 sort -u). From uniq(1): "INPUT (또는 표준 입력)에서 인접한 일치하는 라인을 필터링하여 OUTPUT (또는 표준 출력)에 기록합니다."
Mikael S

아, 당신은 uniq 전에 정렬에 대한 권리입니다. 나는 uniq가 인접한 라인에서만 작동한다는 것을 결코 깨닫지 못했습니다. 나는 항상 sort -u를 사용한다고 생각한다.
Javid Jamae
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.