如何从文件 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
.
我需要先做一些背景介绍,因为也许有更简单的解决方案,但我们会看到的。
所以我有一个包含文档名称的特定格式(列)和顺序的文件。这个文件有超过 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
.