如何从文件 A 中删除文件 B 的内容 - 可能重复

How to remove content of file B from file A - duplicates possible

我需要先做一些背景介绍,因为也许有更简单的解决方案,但我们会看到的。

所以我有一个包含文档名称的特定格式(列)和顺序的文件。这个文件有超过 850000 行。我最初的任务是找到所有需要删除的文档。通常这些文档在最后一列中有一些数值,例如 VC99。 所以我的任务是删除所有标有 VC 值的文档。 文档以大写字母开头,并在第四列中有一些数字,例如 04。为了确定本文档的结尾位置,我必须找到以两个或更多大写字母开头并且在列中具有特定值的行(等于或小于前一个) . 例如,正如您在下面看到的,文档以 ABC 101 开头...它在第四列中的值为 04,在最后一列中标记为 VC99,因此我需要将其与所有子文档一起从文件中删除。

ABC 101 11/11   =       R1A     04      BLABLABLA BLAAAA  ASDDSASDA SADDA           VC22!VC23!VC24!VC25!VC26!VC99!VC27!VC28!VC29!VC30
9476-ABC 555 55/55              B2Z
345 34-BGF 957 22/55            A       3       FREE    ASDADADADADAD.
1551-YTR 101 41/15              A       4/3     FREE    ADADADADADADADADADADADADA              XP1
123 00-DFG 111 11               D       4/3     FREE    ADASDADASDASDADADADAD
1/190 06-YTR 101 11             D       4/3     FREE    ASDADADASD ADADADA ASDADADASDA ADSADADADA
BFD 290 01/28   =       D4B     05      BLABLABLA       
1095-ANT 290 01/28              G2Z
131 61-ANT 290 01/28            A       3       FREE    SASDADADADADAD.
1551-ANT 290 01/27              A       4/3     FREE    SASDADADAASDADADADADASDADADADADAD       XP1
1/155 18-ANT 290 01/10          A       4/3     FREE    ASDADADADADAD             XP1
21/155 18-ANT 290 01/21         A       4/1     FREE    ASDADADADADADASDADADADADAD
DFT 290 9985    =       T4      03      BLOCK   APCLOB  XIG/DO
1095-DFG 290 9985               R2
1551-DFG 290 9985               B       1/7     FREE    ASDADADADADAD
1/1551-DFG 290 9985             B       1/7     FREE    FASDADADADADADARASDADADADADAD AASDADADADADADOB
2/155 18-DFG 290 9985           A       1/L     FREE    AASDADADADADAD PASDADADADADAD CASDADADADADAD ASDADADADADAD
1/190 83-DFG 290 9985           A       1/L     FREE    APASDADADADADADON PASDADADADADADL ASDADADADADAD ASDADADADADAD
131 61-DFG 290 9985             B       3       FREE    SASDADADADADADPEC.
DZZB 987 2242   =       F5Y     04      SOFTWARE UNIT   APCLOBU XIG/DO
1095-DFGY 987 2242              R2A
190 55-DFGY 987 2242            J       1/2/7   FREE    SASDADADADADADO.
155 14-DFGY 987 2242            D       2/7     FREE    APASDADADADADADURV
2/109 26-DFGY 987 2242          B       3/7     FREE    CHAASDADADADADADTION
5/109 26-DFGY 987 2242          D       3/7     FREE    CHASDADADADADADRMAASDADADADADADON
190 73-DFGY 987 2242            B       3/7     FREE    AASDADADADADADRAM
152 01-DFGY 987 2242            -----   B
ZXC 290 0004    =       T5      03      FUNCTION BLOCK  CAPPGEN XIG/D           VC22!VC23!VC24!VC25!VC26!VC99!VC27!VC28!VC29!VC30
1095-DFG 290 0004               R2
2/155 18-DFG 290 0004           B       1/L     FREE    CAPASDADADADADADN
131 61-DFG 290 0004             B       3       FREE    STRUASDADADADADADC.
1551-DFG 216 2530               B       4/1/7   FREE    BLOASDADADADADADNTING
1/1551-DFG 216 2530             B       4/1/7   FREE    BLOCASDADADADADADHART
1/190 83-DFG 216 1642           J       4/1/L   FREE    CALASDADADADADADTHASDADADADADADCASDADADADADADG
DFFT 987 9426   =       D5W     02      SOFTWARE UNIT   CAASDADADADADADNU        XIG/DO
1095-DFGY 987 9426              DF2
190 55-DFGY 987 9426            E       1/2/7   FREE    CAASDADADADADADAM
155 14-DFGY 987 9426            C       2/7     FREE    CAPPASDADADADADADRV
3/109 26-DFGY 987 9426          C       3/7     FREE    CHAASDADADADADADTION
4/109 26-DFGY 987 9426          C       3/7     FREE    CASDADADADADADON
5/109 26-DFGY 987 9426          B       3/7     FREE    CHASDADADADADADTION
190 73-DFGY 987 9426            D       3/7     FREE    CAASDADADADADADAM
152 01-DFGY 987 9426            ZX4     B
1/1521-DFGY 987 9426            C       3/7     FREE    BLASDADADADADADASDADADADADADASDADADADADADINT
2/152 83-DFGY 987 9426          B       3/7     FREE    BAASDADADADADADDADADADADASDADADADADADPORASDADADADADADPGEN

在此示例中,应删除从 ABC 101 11/11 到 DFT 290 9985 的每一行。 然后再次删除从 ZXC 290 0004 到 DFFT 987 9426 的所有内容。 基本上我们可以说我想删除两个模式之间的任何东西,这就是我开始的方式。

我的总体想法是从第四列中提取所有标有 VC99 的文档名称和值,我已经使用此命令完成了此操作

grep "^[A-Z][A-Z].*=.*0[0-7].*V.[9-9][9-9].*" base.txt | awk -F "\t" {'printf ("%5s\t%s\n", , )'} > delete

此时我有一个名为 delete 的文件,文件名称和值分配给它两个值,它看起来像这样

ABC 101 11/11   04
ZXC 290 0004    03

不幸的是,很多名称都包含斜杠,所以我无法轻松地将它们传递给我的下一个 awk 命令,这是路上的第一个颠簸,但我已经找到了解决方案。 我已经使用 sed 来转义斜杠几次,以便下一个 awk 命令可以工作。

sed 's#/#\\/#g' delete > delete_fixed

现在我的固定文件看起来像这样

ABC 101 11\/11 04
ZXC 290 0004    03

现在我可以将这些变量传递给 awk 并使用我在这个门户网站上部分找到的这个小脚本搜索模式。

while IFS=$'\t' read var1 var2
do
awk -F "\t" '/^'"$var1"'/{flag=1;print;next}/^[A-Z][A-Z]/ && ( <= '"$var2"'){flag=0}flag' base.txt >> output
done < delete_fixed

经过几次测试,我确信我有一个完整的行列表,我需要从我的 base.txt 中删除,对于这个例子看起来像这样

ABC 101 11/11   =       R1A     04      BLABLABLA BLAAAA  ASDDSASDA SADDA           VC22!VC23!VC24!VC25!VC26!VC99!VC27!VC28!VC29!VC30
9476-ABC 555 55/55              B2Z
345 34-BGF 957 22/55            A       3       FREE    ASDADADADADAD.
1551-YTR 101 41/15              A       4/3     FREE    ADADADADADADADADADADADADA              XP1
123 00-DFG 111 11               D       4/3     FREE    ADASDADASDASDADADADAD
1/190 06-YTR 101 11             D       4/3     FREE    ASDADADASD ADADADA ASDADADASDA ADSADADADA
BFD 290 01/28   =       D4B     05      BLABLABLA       
1095-ANT 290 01/28              G2Z
131 61-ANT 290 01/28            A       3       FREE    SASDADADADADAD.
1551-ANT 290 01/27              A       4/3     FREE    SASDADADAASDADADADADASDADADADADAD       XP1
1/155 18-ANT 290 01/10          A       4/3     FREE    ASDADADADADAD             XP1
21/155 18-ANT 290 01/21         A       4/1     FREE    ASDADADADADADASDADADADADAD
ZXC 290 0004    =       T5      03      FUNCTION BLOCK  CAPPGEN XIG/D           VC22!VC23!VC24!VC25!VC26!VC99!VC27!VC28!VC29!VC30
1095-DFG 290 0004               R2
2/155 18-DFG 290 0004           B       1/L     FREE    CAPASDADADADADADN
131 61-DFG 290 0004             B       3       FREE    STRUASDADADADADADC.
1551-DFG 216 2530               B       4/1/7   FREE    BLOASDADADADADADNTING
1/1551-DFG 216 2530             B       4/1/7   FREE    BLOCASDADADADADADHART
1/190 83-DFG 216 1642           J       4/1/L   FREE    CALASDADADADADADTHASDADADADADADCASDADADADADADG

正如您可以假设的那样,我被卡住了。 我不知道如何从我的 base.txt 文件中删除那些确切的行。 我试过 grep

grep -F -x -v -f output base.txt > final

但它太贪心了,删除了太多可能重复的 cos。

最糟糕的是我不能对这个文件进行排序,也不能改变它的结构,因为这个文件将被导入到其他工具中,所以我只能删除行。

我也尝试过 diff 以仅查看差异,但 diss 添加了一些字符并更改了结构(或者我不知道如何正确使用它)。

我的想法是以某种方式从第一个完全匹配的行开始删除,然后向下进行,不要回到文件的开头或类似的地方。或者也许有一种方法可以与我的 awk 模式搜索一起使用?

此时如有任何建议,我将不胜感激。

您可以理清 awk 中的逻辑,这比使用多种工具更容易。以下 awk 代码将检查 document/sub-document header 行,然后设置一个标志 (skip) 以确定是否应跳过或打印一行。

$ cat t.15.awk
BEGIN { FS = OFS = "\t"; }

# document/subdocument header started with at least two Uppercase letters 
# and only contain numbers in the 4th field.
function is_document_header() {
    return /^[A-Z][A-Z]/ &&  ~ /^[0-9]+$/
}

# the target document header must have VC99 as a standalone word in the last column
function has_vc99() {
    return $NF ~ /\<VC99\>/
}

# find the line matching document/subdocument header, flag it accordingly
is_document_header() {
    # set up the skip flag
    skip = has_vc99() ? 1 :  <= prev_f4 ? 0 : skip;

    # save  in the previous docuement header to prev_f4, remove
    # the if(..) condition if sub-documents also counted
    if (has_vc99()) prev_f4 = ;
}

# print only when skip is 0
!skip { print }

然后 运行 awk 命令:

$ awk -f t.15.awk file.txt

顺便说一句。在您的示例文本中,以 ABC 101 开头的第一个文档不包含 VC99.