설명하다

설명하다

이 사이트의 첫 번째 질문이므로 잘 설명하지 못하더라도 양해해 주시기 바랍니다. 나도 초보자입니다. Perl 및 Unix 명령줄 항목을 조사했지만 이 문제를 해결하는 방법을 알 수 없습니다.

2개의 파일이 있습니다. 파일 A는 기본 파일이고 10개가 넘는 열과 약 15,000개의 행을 포함하고, 파일 B에는 4개의 열과 약 1500개의 행이 포함되어 있습니다.

파일 B의 각 행을 한 번에 하나씩 가져오고 해당 열을 파일 A의 해당 열과 일치시키고 싶습니다(두 파일의 순서는 다르지만 열 헤더는 동일함). 파일 A에 있는 파일 B의 4개 열이 모두 일치하면 파일 A에서 전체 행을 삭제하고 새 파일(파일 C)에 배치합니다.


예:

파일 A

individual_id   study_id.x  chromosome  g_start gene    referencel1hs   SampleFile_num  id  sample_name
54  Baillie2011 4   57497067    na  no  612 612 DonorAR2
54  Baillie2011 X   154790187   TMLHE   no  612 612 DonorAR2
54  Baillie2011 5   159351203   ADRA1B  no  612 612 DonorAR2
54  Baillie2011 13  79259801    na  no  612 612 DonorAR2
54  Baillie2011 8   4452925 CSMD1   no  610 610 DonorAH

문서 B

study_id.x  sample_name chromosome  g_start
Baillie2011 DonorAH 8   4452925
Baillie2011 DonorBC 9   5491376
Baillie2011 DonorAH 8   5829283
Baillie2011 DonorCH 8   5829283

결과:

파일 A

individual_id   study_id.x  chromosome  g_start gene    referencel1hs   SampleFile_num  id  sample_name
54  Baillie2011 4   57497067    na  no  612 612 DonorAR2
54  Baillie2011 X   154790187   TMLHE   no  612 612 DonorAR2
54  Baillie2011 5   159351203   ADRA1B  no  612 612 DonorAR2
54  Baillie2011 13  79259801    na  no  612 612 DonorAR2

파일C

individual_id   study_id.x  chromosome  g_start gene    referencel1hs   SampleFile_num  id  sample_name
54  Baillie2011 8   4452925 CSMD1   no  610 610 DonorAH

답변1

perl -MFatal='open,close' -ali -ne '
   if ( @ARGV ) { # FileB readin
      if ( $. == 1 ) { push @names, @F;      }
      else           { push @A, join $/, @F; }
      print;
   } else { # FileA readin
      if ( $. == 1 ) {
         open FILEC, ">", "FileC.out";
         print FILEC $_;
         print;
         @remap =
            map {
               my $n = $names[$_];
               grep { $n eq $F[$_] } 0 .. $#F;
            } 0..$#names;
      } else {
         my $n = join $/, @F[@remap];
         if ( grep { $n eq $_ } @A ) { print FILEC $_; }
         else                        { print;          }
      }
   }
   eof and $. = 0;
   eof() and close FILEC;
' FileB FileA

설명하다

  • Perl 명령줄에 "FileB"와 "FileA"라는 두 개의 파일을 순서대로 제공합니다.
  • FileB를 읽는 과정에서 첫 번째 줄인지 다른 줄인지에 따라 두 가지 작업을 수행합니다.
    • FileB의 첫 번째 행에 대해 FileB 필드의 이름을 배열에 저장합니다 @names.
    • 다른 행의 경우 기본적으로 제공되는 @A줄바꿈으로 연결된 필드로 배열을 채웁니다 .\n$/RS
    • Perl두 경우 모두 s 모드 -i에서 FileB를 손실 없이 읽기 위해 이 줄을 STDOUT에 인쇄합니다 .
  • 이제 FileA를 읽을 때 파일을 FILEC채울 수 있도록 첫 번째 줄에서 쓰기 파일 핸들을 엽니다 FileC.out.
    • FileB에서 이 줄을 유지하고 싶기 때문에 STDOUT으로 인쇄합니다.
    • 또한 헤더가 FileC.out에도 들어가도록 하기 위해 파일 핸들 FILEC에 인쇄합니다.
    • 이제 이는 FileB의 필드가 FileA의 필드에 매핑되는 중요한 단계입니다.
  • FileA의 첫 번째가 아닌 행에 대해 우리는 이러한 다시 매핑된 필드와 이미 배열에 저장된 FileB 데이터 간의 동일성 검사를 수행합니다 @A.
  • 일치하는 항목이 발견되면 이 줄을 FileC.out에 쓰고 FileA에는 쓰지 않습니다. 일치하는 항목이 없으면 FileA는 기록되지만 FileC.out은 기록되지 않습니다.
  • 두 파일의 끝에서 줄 카운터를 $.0으로 재설정하여 첫 번째 줄 동일성 검사가 두 파일 모두에서 수행될 수 있도록 합니다.
  • 마지막 eof(eof()를 통해 감지됨) 후에 파일 핸들 FILEC를 닫습니다.
  • 이 모듈은 이러한 작업을 Fatal.pm로드 open하고 close자동으로 종료하는 기능을 가지고 있습니다.

관련 정보