csv 파일을 조회 열 1과 비교하고 열 2의 값을 확인합니다.

csv 파일을 조회 열 1과 비교하고 열 2의 값을 확인합니다.

좋아, 내가 무엇을 해야 하는지 설명하려고 노력할게. 기본적으로 아래 예와 같이 두 개의 CSV 파일이 있습니다.

파일 1:

Column 1, Column 2
abc     , 123
def     , 234
adf     , 567

파일 2

Column 1, Column 2
abc     , 123
def     , 234
adf     , 578

다음을 수행하려면 쉘 스크립트나 간단한 명령을 작성해야 합니다.

  1. 열 1을 기준으로 두 파일 정렬
  2. 다음을 한 줄씩 수행하십시오.
    • 파일 1의 열 1을 사용하여 파일 2의 열 1에서 값을 검색합니다.
      1. 찾은 경우 파일 1의 열 2에 있는 값을 파일 2의 열 2에 있는 값과 비교합니다.
      2. 일치하는 경우 1, 2, 3열에 "확인됨"이라고 써서 파일을 분리하세요.
      3. 일치하는 항목이 없으면 열 1, 열 2 및 "실패"를 파일별로 작성합니다.

그러면 두 개의 출력 파일이 생성됩니다. 첫 번째 파일에는 일치하는 열 1과 2에서 발견된 모든 항목이 포함되고, 두 번째 파일에는 실패한 열 1 조회 또는 발견된 열 1이 포함되지만 열 2 위치에는 일치 항목이 없으므로 기본적으로 열 1을 키로 사용합니다. 2열을 확인하세요.

답변1

다음 입력 파일이 주어지면:

$ cat in1 in2
Column 1, Column 2
abc     , 123
def     , 234
adf     , 567
Column 1, Column 2
abc     , 123
def     , 234
adf     , 578

먼저 이를 정렬한 다음 단일 파일로 연결할 수 있습니다.

$ sort in1 > in1.sorted; sort in2 > in2.sorted; paste in{1,2}.sorted
Column 1, Column 2  Column 1, Column 2
abc     , 123   abc     , 123
adf     , 567   adf     , 578
def     , 234   def     , 234

awk여기서는 쉼표가 도움이 되지만, 먼저 쉼표를 제거해야 합니다 sed.

$ paste in{1,2}.sorted | sed s/,//g
Column 1 Column 2   Column 1 Column 2
abc      123    abc      123
adf      567    adf      578
def      234    def      234

그런 다음 다음을 통해 빠르게 덤프할 수 있습니다 awk.

$ paste in{1,2}.sorted | sed s/,//g | awk '$2 == $4 {print $1,"Validated"}; $2 != $4 { print $1,"Failed"}'
Column Failed
abc Validated
adf Failed
def Validated

이 작업은 raw 를 사용하여 수행할 수도 있습니다 awk. 헤더 행을 제거할 수 있고 동일한 순서의 동일한 데이터에 의존하지 않으므로 정렬이 필요하지 않다는 장점이 있습니다.

$ awk 'FNR != 1 && NR == FNR {data[$1]=$3} FNR != 1 && NR != FNR {if(data[$1]==$3) {print $1, "Validated"} else {print $1, "Failed"} }' in{1,2}
abc Validated
adf Failed
def Validated

이는 몇 가지 마법의 awk내장 변수와 이와 관련된 트릭에 의존합니다.

  • NR-처리된 총 레코드 수
  • FNR- 총 레코드 수현재 파일에다루다
  • FNR != 1- 각 파일의 첫 번째 줄을 건너뜁니다. (헤더는 데이터로 처리되지 않습니다.)
  • NR != FNR- 첫 번째 파일을 완전히 읽고 후속 파일을 읽기 시작한 후에만 실행됩니다. 이를 통해 data두 번째 파일을 씹기 시작하면 테스트용 배열을 미리 채울 수 있습니다.

답변2

다른 사람이 이 글을 읽고 필요할 경우를 대비해 다음과 같이 문제를 해결했다고 생각합니다. 다시 한 번 감사드립니다.

FNR == NR {
    for (i = 2; i <= NF; i++) { a[i,$1] = $i }
    b[$1];
    next;
}
($1 in b) {                   # check if row in file2 existed in file1
    for (i = 2; i <= NF; i++) {
        if (a[i,$1] == $i)
            printf("%s->col%d: %s vs %s: Valid\n", $1, i-1, a[i,$1], $i);
        else
            printf("%s->col%d: %s vs %s: Failure\n", $1, i-1, a[i,$1], $i);
    }
    delete b[$1];   # delete entries which are processed
}

END {
    for (left in b) {   # look which didn't match
        for (i = 2; i <= NF; i++) 
            printf("%s->col%d: %s vs (blank): Not Equal\n", left, i-1, a[i,left])
    }
}

답변3

사용행복하다(이전 Perl_6)

#! /usr/bin/env raku
    
    #INPUT AND HEADERS:

    my $csv1 = "Veyron1.txt".IO;
    my $csv2 = "Veyron2.txt".IO;

    my $hdr1 = "Key,Value,Verified";
    my $hdr2 = "Key,Value,Failed";

    #HASH STORAGE (Below, beware of `skip`ping header in headerless file!):

    my %csv1; for $csv1.lines.skip.map( *.split(",").map( *.trim)) {
                  %csv1.push: .[0] => .[1]
              };
    my %csv2; for $csv2.lines.skip.map( *.split(",").map( *.trim)) {
                  %csv2.push: .[0] => .[1]
              };

    #SANITY CHECKS:

    die "multiple values per key in file_1" if any(%csv1.values.map: *.elems > 1).so; 
    die "multiple values per key in file_2" if any(%csv2.values.map: *.elems > 1).so;

    #OUTPUT FILE PREP W/ HEADER:

    !("Veyron_output_verified.txt".IO.e) && (my $fh1 = "Veyron_output_verified.txt".IO.open: :a); 
    !("Veyron_output_failed.txt".IO.e) && (my $fh2 = "Veyron_output_failed.txt".IO.open: :a); 

    $fh1.put: $hdr1;
    $fh2.put: $hdr2;

    #OUTPUT LOOP:

    for %csv1.keys.sort -> $id {
       if  %csv2{$id}:exists {
           if  %csv1{$id}  eq  %csv2{$id} {
               $fh1.put: ($id, %csv1{$id}, "verified").join: ",";
           }
           else {
               $fh2.put: ($id, %csv1{$id}, "mismatch").join: ",";
           }
       }
       else {
          $fh2.put: ($id, %csv1{$id}, "absent").join: ",";
       }
    }

    $fh1.close;
    $fh2.close;

이것은 Perl 프로그래밍 언어 계열인 Raku로 작성된 스크립트입니다. Perl과 마찬가지로 Raku에는 키/값 데이터 구조와 다양한 파일 연산자가 있어 이러한 성격의 문제를 해결하는 데 이상적입니다. 간단히:

  • 상단의 $-sigiled는 파일 핸들(실제로 는 객체)을 $csv1의미합니다 . Raku에서는 기호가 동일하게 유지되기 때문에 ...$csv2.IO
  • 두 개의 %서명 해시는 %csv1각각 %csv2각 파일에서 얻은 키/값의 저장 위치를 ​​나타냅니다.
  • 공백 자르기, 헤더 조작 및 온전성 검사는 실행 중인 코드에 세부 정보를 추가합니다.
  • "exists"와 같은 파일 연산자는 .e기존 출력 파일을 덮어쓰지 않도록 합니다. 파일 핸들은 :a를 나타내는 옵션과 함께 열립니다 :append.
  • 출력 루프에서 %csv1의 키를 찾아 %csv2확인하세요 .상응하는 문자열( eq동일) values. "확인됨", "일치하지 않음" 또는 "존재하지 않음"의 세 가지 문자열 중 하나를 반환합니다.
  • 출력은 열려 있는 출력 파일 핸들에 한 줄씩 추가되며 스크립트 끝에서 닫힙니다.

참고: 확인하고 싶다면수치적 등가물각 키의 값은 다음과 같습니다.

%csv1{$id} eq %csv2{$id}그리고: %csv1{$id} == %csv2{$id}


출력 예("확인됨"):

Key,Value,Verified
abc,123,verified
def,234,verified

출력 예("실패"):

Key,Value,Failed
adf,567,mismatch

Leku 참고 자료:
https://docs.raku.org
https://raku.org

관련 Perl 스크립트:
https://www.perlmonks.org/?node_id=805106

관련 정보