我需要先做一些背景知识,也许有一个更简单的解决方案,但我们会看到。
所以我有一个特定格式的文件(列)和包含文档名称的顺序。该文件有超过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模式搜索一起使用?
在此,我将感谢您的任何建议。
答案 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
。