根据具有重复模式的列表从文本文件中多次提取行

根据具有重复模式的列表从文本文件中多次提取行

我有一个文件,其中每一行都以唯一标识符开头,例如:

$ cat source.txt
aaa text
bbb text
ccc text
ddd text
eee text

我尝试使用带有选项 -f 的 fgrep 将包含另一个文件(我们称之为“list.txt”)中列出的标识符的行保存到新文件中:

fgrep -f list.txt source.txt > new.txt

问题是“list.txt”中的一些标识符是重复的,例如:

$ cat list.txt
aaa
ccc
ccc
ccc
eee
eee

在这里,grep 将每个重复的标识符视为只列出一次,给出如下结果:

$ cat new.txt
aaa text
ccc text
eee text

相反,我想将包含在 list.file 中重复的标识符的行保存为这些标识符重复的确切次数。在这种情况下,更好的最终结果应该是:

$ cat new.txt
aaa text
ccc text
ccc text
ccc text
eee text
eee text

是否有一些简单的技巧可以强制 grep 停止将重复的标识符视为仅列出一次?或者,是否有其他方法可以在不使用 grep 的情况下获得我想要的结果,例如使用 awk?


为了更好地可视化问题,下面是 source.txt 中的实际行:

head -n 1 source.txt | cat -T
GCF_000005825.2_WP_003320558.1 MULTISPECIES: IS21-like element helper ATPase IstB [Bacillaceae]^IMNEQIQAYAKRLKLSWIRENFNQIEAETNEEYLLKLFEKEVQNREERKVNLLLSQAQLPKTGSTPFQWEHIQIPQGIERTAVINGDFIKERENLILYGGVGTGKTYLATLLSLNAIHRFGSQVKFYTVAGLVNKLIEANQKNTLPKLMKQIEKLDLLILDELGYIPLNKEGAELLFQVISMCYENRSIVITTNLQFGQWNHVFGDPILTEAVIDRLIHHSHLLVFKGDSFRYKESLLHQ

这将是它的匹配标识符:

GCF_000005825.2_WP_003320558.1

答案1

这是一种方法awk(假设source.txt不是太大而不会遇到内存问题)。

$ awk 'NR==FNR{a[$1]=$0; next} $0 in a{print a[$0]}' source.txt list.txt
aaa text
ccc text
ccc text
ccc text
eee text
eee text
  • NR==FNR{a[$1]=$0; next}这会构建一个数组,其中第一个字段作为键,整个输入行作为值(对于第一个文件,source.txt在本例中)
  • $0 in a{print a[$0]}list.txt处理文件时,检查每一行是否作为数组中的键存在a,并打印相应的行

这是一个修改后的解决方案,应该在内存方面表现更好(假设 in 中的行source.txt恰好有两个字段并由单个空格分隔)。

awk 'NR==FNR{a[$1]=$2; next} $0 in a{print $0, a[$0]}'

数组中只保存第二个字段,而不是保存整行。打印时,密钥带有前缀。

答案2

另一种方法,用于xargs完成繁重的工作。

$ grep -v "^$" list.txt | xargs -I{} grep "^{} " source.txt
aaa text
ccc text
ccc text
ccc text
eee text
eee text
$

相关内容