Perl

使用另一個文件從一個管道分隔文件中刪除行的 Perl 腳本有一個匹配的列

  • January 24, 2020

我有兩個大文件,File A包含所有記錄作為管道(|)分隔的列,File B其中有一列。

我需要從File A該列值與File B.

我希望根據文件 A 中的第 2 列檢查文件 B 中的第 1 列

文件 B - 文件 B 中的唯一列

818815504
842019301
880702511

文件 A - 文件 A 中的第二列

2020-01-19|777504559|2|15|1|403941|53|4708267|3036|5033|127380343|0|3905585|C|1168|IRU|107|NR
2020-01-19|818815504|2|15|1|403933|8|2394063|3036|2394067|4076948618|0|15177438|B|1168|CRU|98|NK
2020-01-19|842019301|2|15|1|2|2|3712|3036|961249|65707843|65707843|8591573|B|1168|IRU|1|NJ
2020-01-19|847082255|2|15|1|2|2|284|3036|291|125650195|125650195|8870299|C|1168|IRU|1|NR
2020-01-19|858760375|2|15|1|403941|53|4708267|3036|306|99931425|0|8866849|C|1168|IRU|107|NR
2020-01-19|869323039|2|15|1|2|2|371|3036|307|106104029|106104029|4518435|C|1168|IRU|2|NR
2020-01-19|872268371|2|15|1|403941|53|4708267|3036|143|127382679|0|8866849|C|1168|IRU|107|NR
2020-01-19|858760375|2|15|1|2|2|117|3036|109|2739523|5208959|4037061|C|1168|IRU|2|NR

假設結果的順序不重要:

$ join -v 1 -t '|' -1 2 <( sort -t '|' -k2,2 fileA ) <( sort fileB )
777504559|2020-01-19|2|15|1|403941|53|4708267|3036|5033|127380343|0|3905585|C|1168|IRU|107|NR
847082255|2020-01-19|2|15|1|2|2|284|3036|291|125650195|125650195|8870299|C|1168|IRU|1|NR
858760375|2020-01-19|2|15|1|2|2|117|3036|109|2739523|5208959|4037061|C|1168|IRU|2|NR
858760375|2020-01-19|2|15|1|403941|53|4708267|3036|306|99931425|0|8866849|C|1168|IRU|107|NR
869323039|2020-01-19|2|15|1|2|2|371|3036|307|106104029|106104029|4518435|C|1168|IRU|2|NR
872268371|2020-01-19|2|15|1|403941|53|4708267|3036|143|127382679|0|8866849|C|1168|IRU|107|NR

join實用程序對給定的兩個數據集執行關係 INNER JOIN 操作。數據集必須在我們加入的列上進行排序,這就是我們在呼叫之前對文件進行排序的原因join(如果您的 shell 不支持程序替換,請單獨對文件進行預排序)。join我們在此處使用的選項-t '|'-1 2表示“|用作列分隔符,並在第一個數據集的第二列上連接”(第一列是預設值)。

-v 1我們請求第一個文件中不能與第二個文件中的行配對的所有行。

輸出將始終首先列出連接列,因此我們可能希望通過使用交換前兩個列將其移動到正確位置awk

$ join -v 1 -t '|' -1 2 <( sort -t '|' -k2,2 fileA ) <( sort fileB ) | awk 'BEGIN { FS=OFS="|" } { t=$1; $1=$2; $2=t; print }'
2020-01-19|777504559|2|15|1|403941|53|4708267|3036|5033|127380343|0|3905585|C|1168|IRU|107|NR
2020-01-19|847082255|2|15|1|2|2|284|3036|291|125650195|125650195|8870299|C|1168|IRU|1|NR
2020-01-19|858760375|2|15|1|2|2|117|3036|109|2739523|5208959|4037061|C|1168|IRU|2|NR
2020-01-19|858760375|2|15|1|403941|53|4708267|3036|306|99931425|0|8866849|C|1168|IRU|107|NR
2020-01-19|869323039|2|15|1|2|2|371|3036|307|106104029|106104029|4518435|C|1168|IRU|2|NR
2020-01-19|872268371|2|15|1|403941|53|4708267|3036|143|127382679|0|8866849|C|1168|IRU|107|NR

僅使用awk

$ awk -F '|' 'FNR==NR { key[$1]=1; next } !($2 in key)' fileB fileA
2020-01-19|777504559|2|15|1|403941|53|4708267|3036|5033|127380343|0|3905585|C|1168|IRU|107|NR
2020-01-19|847082255|2|15|1|2|2|284|3036|291|125650195|125650195|8870299|C|1168|IRU|1|NR
2020-01-19|858760375|2|15|1|403941|53|4708267|3036|306|99931425|0|8866849|C|1168|IRU|107|NR
2020-01-19|869323039|2|15|1|2|2|371|3036|307|106104029|106104029|4518435|C|1168|IRU|2|NR
2020-01-19|872268371|2|15|1|403941|53|4708267|3036|143|127382679|0|8866849|C|1168|IRU|107|NR
2020-01-19|858760375|2|15|1|2|2|117|3036|109|2739523|5208959|4037061|C|1168|IRU|2|NR

這首先讀取我們要提取到關聯數組中的數字key。然後,當解析第二個文件時,如果第二個欄位不是該數組中的鍵,則列印該行。

這將按照它們在該文件中出現的順序輸出行fileA,但缺點是所有數字都fileB需要保存在記憶體中。


根據要求使用 Perl:

$ perl -F'\|' -le 'if (!$flag){ $key{$F[0]}=1 } elsif ($key{$F[1]}!=1) { print $_ }; if (!$flag && eof) { $flag=1 };' fileB fileA
2020-01-19|777504559|2|15|1|403941|53|4708267|3036|5033|127380343|0|3905585|C|1168|IRU|107|NR
2020-01-19|847082255|2|15|1|2|2|284|3036|291|125650195|125650195|8870299|C|1168|IRU|1|NR
2020-01-19|858760375|2|15|1|403941|53|4708267|3036|306|99931425|0|8866849|C|1168|IRU|107|NR
2020-01-19|869323039|2|15|1|2|2|371|3036|307|106104029|106104029|4518435|C|1168|IRU|2|NR
2020-01-19|872268371|2|15|1|403941|53|4708267|3036|143|127382679|0|8866849|C|1168|IRU|107|NR
2020-01-19|858760375|2|15|1|2|2|117|3036|109|2739523|5208959|4037061|C|1168|IRU|2|NR

這模仿了awk程序,但是由於 Perl 沒有單獨的NRFNR內置的變數,我們需要維護一些狀態($flag)來告訴我們目前是在解析第一個文件還是第二個文件。

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