[linux] 열별로 ‘유니크’하는 방법이 있습니까?

다음과 같은 .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작동하지 않습니다.



답변

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 


답변

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

답변

여러 열을 고려합니다.

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

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

답변

또는 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


답변

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

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

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

여기

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


답변

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

먼저 고유성을 비교할 열이 고정 너비가되도록 내용의 형식을 지정하십시오. 이를 수행하는 한 가지 방법은 필드 / 열 너비 지정자 ( “% 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 }'


답변

주어진 파일에 대해 특정 값을 가진 모든 것을 제거 해야하는 경우 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 패턴은 실제로 “[^ |] +”(예 : 구분 기호가 아닌 것)와 같아야합니다. 그러나 이것은 충분히 명확합니다.