![解析一个文件,其中包含来自其他文件的多个数据](https://linux22.com/image/184179/%E8%A7%A3%E6%9E%90%E4%B8%80%E4%B8%AA%E6%96%87%E4%BB%B6%EF%BC%8C%E5%85%B6%E4%B8%AD%E5%8C%85%E5%90%AB%E6%9D%A5%E8%87%AA%E5%85%B6%E4%BB%96%E6%96%87%E4%BB%B6%E7%9A%84%E5%A4%9A%E4%B8%AA%E6%95%B0%E6%8D%AE.png)
我想根据 a.txt 中的 3 个数据(A、B、num : xxx)选择 b.txt 中的行。
a.txt
A B num : 580
A B num : 581
A B num : 582
b.txt
10 E1 A Z1 B Z2 num : 580 Z3 582 Z4
11 E2 C Z1 B Z2 num : 581 Z3 580 Z4
12 E3 A Z1 B Z2 num : 581 Z3 580 Z4
14 E3 S Z1 B Z2 num : 582 Z3 581 Z4
15 E2 A Z1 B Z2 num : 582 Z3 581 Z4
输出
10 E1 A Z1 B Z2 num : 580 Z3 582 Z4
12 E3 A Z1 B Z2 num : 581 Z3 580 Z4
15 E2 A Z1 B Z2 num : 582 Z3 581 Z4
我的代码
awk 'NR==FNR{pattern[$0];next} ($3 && $5 && "$7 $8 $9" in pattern)' a.txt b.txt > GoodFile.txt
这有什么问题吗?谢谢。
答案1
关联数组的键pattern
是字符串连接字段和字段分隔符,即
$ awk 'NR==FNR{pattern[$0]; next} $3" "$5" "$7" "$8" "$9 in pattern' a.txt b.txt
10 E1 A Z1 B Z2 num : 580 Z3 582 Z4
12 E3 A Z1 B Z2 num : 581 Z3 580 Z4
15 E2 A Z1 B Z2 num : 582 Z3 581 Z4
或者也许更稳健(因为它不假设分隔符是a.txt
单个空格),利用明确的SUBSEP
awk 变量正如埃德·莫顿建议的那样:
awk 'NR==FNR{pattern[$1,$2,$3,$5]; next} ($3,$5,$7,$9) in pattern' a.txt b.txt
答案2
利用GNU sed
打开的扩展正则表达式模式-E
和关闭的自动打印模式空间-n
,我们可以如图所示解决它。
首先,我们定义一些辅助 shell 变量来简化 sed 代码的编写。
$ f='(\S+)' g='\s+\S+\s+' fg="$f$g"
$ Ss='\S+\s+' fs="$f\s+"
$ re="$Ss $Ss $fg $fg $fs $fs $fs"
$ sed -En "
s/$f/&/6;tb
s/\s+/ /g;s/^ | \$//g
H;d
:b;G
\#^${re// /}.*\n\1 \2 \3 \4 \5(\n|$)#P
" a.txt b.txt
¶ 首先,我们通过存在的第 6 个非空格块来识别来自 a.txt 或 b.txt 的行。如果是,则为文件 b.txt,我们跳转到 sed 代码中的标签 b。
¶ 否则,对于文件 a.txt,我们修剪行并压缩空格。然后存放。
¶ 对于文件 b.txt 中的行,我们插入 $re shell 变量,该变量是根据 b.txt 的行结构编写的。另外,在编写它时,为了清晰起见,我们在其中撒了空格,现在我们必须将其删除。P
如果 b.txt 的块编号 3、5、7,8 和 9 在 a.txt 的一行中的任何位置找到,我们将打印模式空间的前导部分。