Perl

如果文件 B 中的行與文件 A 中的多個列匹配,則刪除文件 A 中的行

  • July 20, 2017

這是我在這個網站上提出的第一個問題,所以如果我解釋得不好,請原諒。我也是新手。我研究了一些 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
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 的命令行提供 2 個文件“FileB”和“FileA”。

  • 在讀取 FileB 期間,根據我們是在第一行還是其他行,我們會做兩件事:

    • 對於 FileB 的第一行,我們將 FileB 欄位的名稱儲存到數組@names中。
    • 對於其他行,我們使用由預設情況下提供@A的換行符連接的欄位填充數組。\n``$/``RS
    • 在這兩種情況下,我們將這些行列印到 STDOUT,以便 FileB 在Perl-i模式下被非破壞性地讀取。
  • 現在,當我們讀取 FileA 時,在它的第一行,打開一個寫入文件句柄FILEC,以便我們能夠填寫FileC.out文件。

    • 我們列印到 STDOUT,因為我們希望 FileB 中的這一行保留。
    • 我們還列印到文件句柄 FILEC,因為我們希望標頭也進入 FileC.out。
    • 現在這是關鍵步驟,其中將 FileB 的欄位映射到 FileA 的欄位。
  • 對於 FileA 中的非第一行,我們使用數組中 FileB 中已儲存的數據對這些重新映射的欄位執行相等性檢查@A

  • 如果找到匹配項,則將此行寫入 FileC.out 但不要寫入 FileA。如果未找到匹配項,則我們寫入 FileA 但不在 FileC.out 中。

  • 在任一文件的 eof 後,我們將行計數器重置$.為 0,以便可以執行兩個文件的第一行相等性檢查。

  • 在最終的 eof(通過 eof() 檢測到)時,我們關閉文件句柄 FILEC。

  • 該模組Fatal.pm已載入openclose具有對這些操作執行自動退出的功能。

引用自:https://unix.stackexchange.com/questions/379728