
awk를 사용하여 중복 항목을 삭제하는 것은 매우 일반적이고 간단합니다. 하지만 하나의 열만 비교할 때 중복되는 줄만 인쇄해야 합니다. 나는 다음 명령을 시도했습니다.
awk 'seen[$2]++'
하지만 보시다시피 결함이 있습니다. 중복된 내용이 인쇄되지만 두 번째 등장 이후에만 가능합니다. 나는 이제 유닉스와 배시에 익숙해지기 시작했는데, 나에게 해결책을 설명해 주시면 좋을 것 같습니다.
답변1
이를 수행하는 두 가지 방법을 볼 수 있습니다.
파일을 두 번 반복합니다.
첫 번째 반복에서는 $2가 나타나는 횟수를 셉니다.
두 번째 반복에서는 개수가 1보다 큰 줄만 인쇄합니다.awk 'NR == FNR {count[$2]++; next} count[$2] > 1' file file
데이터의 단일 반복으로:
$2가 나타나는 횟수를 세어야 합니다.그리고각 $2에 대해 어떤 줄이 발생했는지 기억하세요.
이 답변은 배열 배열에 GNU awk를 사용합니다. 출력 순서는 입력 데이터와 동일하지 않을 수 있습니다. 또한 전체 파일을 메모리에 저장해야 합니다.
gawk ' { lines[$2][++count[$2]] = $0 } END { for (x in lines) if (count[x] > 1) for (i=1; i<=count[x]; i++) print lines[x][i] } ' file
입력 파일로 테스트되었습니다.
$ cat file
a b
b b
c b
a c
a d
b d
a e
및 예상 출력
a b
b b
c b
a d
b d
답변2
동일한 샘플 입력 사용글렌 잭맨님의 답변
$ awk '$2 in seen{if(c[$2]--){print fl[$2]} print} !seen[$2]++{fl[$2]=$0; c[$2]=1}' file
a b
b b
c b
a d
b d
!seen[$2]++
$2
이전에 발생하지 않은 경우 :fl[$2]=$0
이 첫 번째 줄을 저장하십시오. 입력이 정렬되지 않고 파일의 어느 곳에서나 중복이 발생할 수 있다고 가정했기 때문에$2
임시 변수 대신 에 저장합니다.c[$2]=1
마찬가지로 count 변수를 1로 초기화합니다.
$2 in seen
$2
이전에 발생한 경우 :if(c[$2]--){print fl[$2]}
먼저 이전 줄을 인쇄하고, 후속 일치에 대한 조건이 실패하도록 카운터가 감소됩니다.print
그런 다음 현재 줄을 인쇄하십시오.
다른 입력으로
$ cat ip.txt
6.2 : 897 : bar
3.1 : 32 : foo
1.2 : 123 : xyz
2.3 : 32 : baz
7.5 : 897 : boo
$ awk -F: '$2 in seen{if(c[$2]--){print fl[$2]} print} !seen[$2]++{fl[$2]=$0; c[$2]=1}' ip.txt
3.1 : 32 : foo
2.3 : 32 : baz
6.2 : 897 : bar
7.5 : 897 : boo
순서는 중복이 발생하는 방식에 따라 달라집니다.
답변3
동일한 파일을 두 번 반복할 때 행 번호를 편리한 색인으로 사용할 수 있습니다. 더 깨끗한 논리를 만들 수 있습니다.
awk 'NR == FNR {if ($2 in z) { y[z[$2]]; y[FNR] } z[$2]=FNR; next} (FNR in y)' file file
나는 이 질문에 대한 대답에서 비슷한 방법을 사용했습니다.
이 트릭의 기본은 Awk가 단순히 변수를 참조하여 변수를 생성하고 index in arrayname
배열 요소가 지정된 인덱스로 생성되었는지 여부에 따라 구성이 true 또는 false를 반환한다는 것입니다.