Sed 基于第一行返回多行,其中包含来自第二个文件的查询

Sed 基于第一行返回多行,其中包含来自第二个文件的查询,sed,Sed,我有一个大文件(~4000000行),由多个数据块组成,每个数据块都有一个介绍性的ID标记,第二个文件中有一个选定的ID标记列表 例如: Data.txt >ID:1000 data about this more data data >ID:1001 blah blah data >ID:1002 foo ... 和ID_Tags.txt >ID:1000 >ID:1002 >ID:1085 >ID:3062 ... 我需要一种方法从data.tx

我有一个大文件(~4000000行),由多个数据块组成,每个数据块都有一个介绍性的ID标记,第二个文件中有一个选定的ID标记列表

例如:

Data.txt

>ID:1000
data about this
more data
data
>ID:1001
blah blah
data
>ID:1002
foo
...
和ID_Tags.txt

>ID:1000
>ID:1002
>ID:1085
>ID:3062
...
我需要一种方法从data.txt中获取ID_Tags.txt中指定数据的ID标记和相应数据,这样我就会得到一个如下所示的文件:

选择_Data.txt

>ID:1000
data about this
more data
data
>ID:1002
foo
...
我可以一次获取一个数据块

sed -n '/ID:1000/,/>/p' Data.txt | head -n -1 >> Select_Data.txt

但这一次只做一个ID标记,我有数百个选择ID标记。有没有办法避免手动执行此操作?

您可以使用以下
awk
脚本:

awk 'NR==FNR{i[$1];next} NF>1 && $1 in i{print ">"$0}' RS='>' ids.txt data.txt
输出:

>ID:1000
这方面的数据
更多数据
数据
>身份证号码:1002
等
我的解决方案的关键是使用
RS='>'
将默认的记录分隔符
\n
替换为
。使用此技巧访问数据的各个字段非常简单

解释

我们正在将这两个文件传递给awk、ids.txt和data.txt,awk将按顺序处理它们

NR==FNR{i[$1];next}
运行,除非awk正在解析第一个文件ids.txt
NR
表示当前记录编号,
FNR
表示当前文件中记录的编号。它们仅在解析第一个文件时相等
i[$1]
添加id值(不带前导的
,因为它是字段分隔符)作为数组
i
的键<代码>下一步停止该行的进一步处理

$1 in i{print”>“$0}
将检查数据记录的第一列(id)是否是数组
i
中的键,并在将
添加回该记录的前面时打印该记录

请注意,我们正在另外检查
NF>1
(表示记录不是空的),因为awk将返回一个空的第一条记录,因为数据文件以记录分隔符
开头<数组中的code>将在awk中生成
true
,并将打印和附加

这可能适合您(GNU-sed):


这将从ids文件构建一个sed脚本,并针对数据文件运行该脚本。sed脚本在ids文件中查找这些id,并打印id行和后面的那些行,直到下一个id返回并检查id。所有其他行都将被删除。

谢谢,现在应该修复。通常,您应该测试
NF
,而不是
$0
,决定记录是否为空,因为如果存在值且数值计算结果为零,则对
$0
的测试将失败。在这种情况下,我看不出
$0
如何不希望地计算为零,因为每个记录都以
ID
开头,但这只是一般的经验法则。当然,在这种情况下,测试
NR>1
会更清晰。@EdMorton谢谢Ed,我一直很感谢您的演讲!:)实际上,我建议单独使用
NF
(测试一条空记录)或
NR>1
(测试第二条和后续记录),而不是
NF>1
(测试记录中的多个字段)。那些清晨的讲座很难集中注意力,我想:-)。虽然我已经想到了,但你的讲座看起来干净多了。加1。不客气。如果/当您准备接受答案时,请记住单击答案旁边的复选标记。
$ awk 'NR==FNR{tags[$0];next} /^>/{f=($0 in tags)} f' ID_Tags.txt Data.txt
>ID:1000
data about this
more data
data
>ID:1002
foo
$ awk 'NR==FNR{tags[$0];next} /^>/{f=($0 in tags)} f' ID_Tags.txt Data.txt
>ID:1000
data about this
more data
data
>ID:1002
foo