uniq 열을 무시하는 csv 파일, 어쩌면 awk일까요?

uniq 열을 무시하는 csv 파일, 어쩌면 awk일까요?

이 문서를 보면(주석은 문서의 일부가 아니라 설명의 일부입니다)...

x,a,001,b,c,d,y
x,a,002,b,c,e,yy
x,bb,003,b,d,e,y
x,c,004,b,d,e,y
x,c,005,b,d,e,y   # nb - dupe of row 4
x,dd,006,b,d,e,y
x,c,007,b,d,e,y   # nb - dupe of row 4 and 5
x,dd,008,b,d,f,y
x,dd,009,b,d,e,y   # nb - dupe of row 6
x,e,010,b,d,f,y

...다음과 같은 출력을 얻고 싶습니다.

x,a,001,b,c,d,y
x,a,002,b,c,e,yy
x,bb,003,b,d,e,y
x,c,004,b,d,e,y
x,dd,006,b,d,e,y
x,dd,008,b,d,f,y
x,e,010,b,d,f,y

파일에서 세 번째 열을 제거한 다음 파일에서 uniq를 실행하고 나머지 행의 세 번째 열 값이 올바른 위치에 다시 추가되면 위의 결과를 얻습니다.

하지만 저는 정말로 그런 일을 할 수 있는 뭔가를 생각해내려고 노력하고 있어요. 저는 Linux의 텍스트 처리 유틸리티에 대해 배울 수 있는 기회를 환영했습니다.

성능: 파일이 1MB를 넘기는 것은 불가능해 보이고 하루에 1개의 파일만 생성됩니다.

대상: Debian GNU/Linux 7 amd64, 256MB/Xeon.

편집: 필드가 고정 너비가 아니기 때문에 예제를 적용하면 uniq --skip-chars=n관련된 솔루션이 내가 아는 한 작동하지 않습니다.

답변1

이를 통해 awk다음을 수행할 수 있습니다.

awk -F, -vOFS=, '{l=$0; $3=""}; ! ($0 in seen) {print l; seen[$0]}'

답변2

가장 간단한 방법:

sort -u -t, -k1,2 -k4
  • -u: 다음과 같은 첫 번째 라인만 출력합니다.
  • -t,: 필드 구분자로 쉼표를 사용합니다.
  • -k1,2 -k4: 1,2,4번 필드와 나머지 필드만 정렬

또 다른 옵션은 데이터를 양쪽에서 재배열하는 것입니다 sed(GNU 옵션 참고 -r). 이렇게 하려면 레코드가 대부분 고정 길이여야 합니다. 그렇지 않으면 실패할 것입니다(거의 눈에 띄지 않습니다).

sed -r       's/^([^,]+,[^,]+)(,[^,]+)(.*)$/\1\3\2/' \
    | sort \
    | uniq -w 12 \
    | sed -r 's/^([^,]+,[^,]+)(.*)(,[^,]+)$/\1\3\2/'

필요한 경우 sort숫자로 정렬하기 위해 끝에 다른 항목을 추가 할 수 있습니다(해당 -k옵션을 사용하여 수행해야 하는 정렬을 기준으로 선택 - 예: sed -k3 -t,) .

예를 들어 Perl에서는 고유성을 확인하려는 부분을 해시(전체 행의 값)의 키로 사용하고 키가 아직 정의되지 않은 경우에만 해시를 삽입할 수 있습니다. 이것은 확실히 sed(or awk) 를 사용하는 것보다 더 유연할 뿐만 아니라 더 많은 쓰기 기능을 제공합니다(저는 Perl 전문가와는 거리가 멀기 때문에 더 우아한 방식으로 수행할 수 있습니다. Perl과 유사한 Perl 솔루션에 대한 다른 답변을 참조하세요).

#!/usr/bin/perl
use strict;

my %lines;
while (<>) {
    (my $k1, my $v, my $k2) = /^([^,]+,[^,]+,)([^,]+)(,.*)$/;
    my $k = $k1 . $k2;
    if (!exists($lines{$k})) {
        $lines{$k} = $_;
    }
}

for my $k (sort(keys(%lines))) {
    print $lines{$k};
}

답변3

이를 수행하는 한 가지 방법은 다음과 같습니다 awk | sort | uniq | awk.

awk -F, '{a=$1;$1=$3;$3=a;print}' file | sort -k 2 | uniq -f 1 | awk -v OFS=',' '{a=$1;$1=$3;$3=a;print}'

답변4

더 간단한 Perl 접근 방식은 다음과 같습니다.

perl -F"," -ane '$a=join(",",@F[0,1,3 .. $#F]); print unless $k{$a}; $k{$a}++' file

-a필드를 @F배열 로 분할 하고 -F","필드 구분 기호를 로 설정합니다 ,. 입력 파일의 각 행에서 -n지정된 스크립트를 실행함을 나타냅니다.-e

아이디어는 배열 슬라이스(배열 끝까지 요소 0,1 및 3)를 가져와 문자열( $a)로 연결하고 해당 문자열을 해시(연관 배열) 참조로 사용하는 것입니다. 그런 다음 해시 키가 이전에 표시되지 않은 경우에만 각 줄이 인쇄됩니다.

관련 정보