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

时间:2019-04-05 15:03:23

标签: awk sed grep diff

我需要先做一些背景知识,也许有一个更简单的解决方案,但我们会看到。

所以我有一个特定格式的文件(列)和包含文档名称的顺序。该文件有超过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", $1, $4)'} > 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]/ && ($4 <= '"$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模式搜索一起使用?

在此,我将感谢您的任何建议。

1 个答案:

答案 0 :(得分:0)

与使用多种工具进行比较,您可以更轻松地整理awk中的逻辑。以下awk代码将检查文档/子文档标题行,然后设置一个标志(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]/ && $4 ~ /^[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 : $4 <= prev_f4 ? 0 : skip;

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

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

然后运行awk命令:

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

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