我有一个文件 ( list_file
),它是名称列表,另一个文件 ( data_file
) 包含数十万行文本,每行都以list_file
.我想搜索以data_file
每个名称开头的所有行,list_file
并将每个名称的行导出到一个新文件*.txt
(*
列表中的名称在哪里)
我有这个
grep -f "list_file" data_file > out.txt
但这不会将列表中的每一行分成自己的文件。
样本list_file
:
100_fullA
100_fullB
105_fullA
105_fullB
112_fullA
112_fullB
121_fullA
121_fullB
样本data_file
:
100_fullA NGATCATCGACAC
100_fullB NGATCATCGACAC
105_fullA NGATCATCGACAC
105_fullB NGATCATCGACAC
112_fullA NGATCATCGACAC
112_fullB NGATCATCGACAC
121_fullA NGATCATCGACAC
答案1
您可以从 构造一个查找表(或哈希)list_file
,例如在 中使用关联数组awk
:
awk 'NR==FNR {list[$1]=1; next} $1 in list {print > $1".txt"}' list_file data_file
输出将保存在 files 中100_fullA.txt
,100_fullB.txt
依此类推。
答案2
您可以通过动态构建命令来做到这一点:
grep -f list_file data_file | sed -e "s/^\([^ ]*\).*/echo '&' >> \1;/" | sh
答案3
这是使用 Bash 的解决方案:
#!/bin/bash
while read pointer; do
filename="$(echo $pointer | cut -d ' ' -f 1)"
if grep $filename list_file > /dev/null; then
echo $pointer >> output/"$filename".txt
fi
done < data_file
这是逐行细分:
第 3 行是用于循环访问 data_file 的 while 循环的开始。
第 4 行回显当前迭代中读取的行。然后该行被传递到 cut,它使用空格作为分隔符来剪切该行的第一部分。然后将结果分配给名为“文件名”的变量。
第 5 行使用 grep 来确定 list_file 中是否存在先前确定的值。如果 grep 成功找到该值(返回状态 0),则脚本继续执行第 6 行。如果 grep 未找到任何内容(返回状态 1),则脚本重新开始循环。
第 6 行将整行回显到输出/“$filename”.txt。
第 7 行结束 if 语句。
第 8 行结束循环,并且是引用 data_file 的地方。
其他重要注意事项:
- “output/”目录必须在脚本运行之前创建,否则你会得到类似“output: no such file or directory”的错误。如果这是一个问题,可以通过在脚本开头添加“mkdir output”来轻松解决。
- 您提到 data_file 有数十万行。因此,该脚本可能需要很长时间才能完成。如果您发现自己经常查询此文件以获取信息,则值得将这些信息转换为 MariaDB 或类似的数据库。
- 如果 list_file 还包含许多条目,则该脚本将花费非常长的时间来运行,因为第 5 行的 grep 会在循环的每次迭代中查询整个 list_file。同样,这个问题可以通过 SQL 数据库中的可用工具来解决。