FILE-A 有 100,000 行。 FILE-B 是 50 个搜索词。我希望使用 FILE-B(CSV 或 TXT)中的各种术语来完成 FILE-A(CSV 或 TXT)的搜索,并且 - 这是关键 - 根据搜索将结果保存在单独的 TXT 文件中FILE-B 中的术语。
例子:
文件-A
123
45678
1239870
2349878
39742366876
41967849
789
910
2378
6723
文件-B
1
2
23
78
结果 = "1.txt" 包含来自 FILE-A 的所有匹配行,"2.txt" 包含来自 FILE-A 的所有匹配行,"23.txt"、"78.txt" 等等。因此,如果 FILE-B 有 50 个搜索词,我最终会得到 50 个 TXT 文件,以搜索词命名,假设 FILE-A 中至少有一个与该词匹配的文件。
我使用“fgrep -f FILE-B.txt FILE-A.csv >> output.txt”进行搜索,这会将 FILE-A 中找到的 FILE-B 中的所有搜索项放入一个“output.txt”中。相反,我希望将它们分成单独的文本文件。
答案1
Grep + Xargs
xargs -d '\n' sh -c '
for term; do grep "$term" fileA > "$term.txt"; done
' xargs-sh < fileB
改进为CAS。
格雷普 + 外壳
一般来说使用 shell 循环读取文件是不好的做法,但这里fileB
比它小得多fileA
,因此不会显着影响性能。
while IFS= read -r term; do
grep "$term" fileA > "$term.txt"
done < fileB
awk
awk 'NR==FNR{pat[$0];next}{for(term in pat){if($0~term){print>term}}}' fileB fileA
NR==FNR{pat[$0];next}
读取作为参数给出的第一个文件并将每一行放入数组中pat
。{for(term in pat){if($0~term){print>term}}}
是不言自明的:对于term
数组中的每个元素,测试当前行是否与该术语匹配,如果是,则将其打印到相应命名的文件中。
并非所有 Awks 都允许同时打开多个文件。解决这个问题的一种方法是建议的埃德·莫顿,就是使用close
语句并使用追加运算符:
awk 'NR==FNR{pat[$0];next}{for(term in pat){if($0~term){print>>term;close(term)}}}' fileB fileA
答案2
这应该是有效的,因为它使用第一遍grep -F
(非常快)来输出 FILE-A 中与 FILE-B 中的行匹配的行(这可能比 FILE 中原始的 100,000 行要少得多) -A) 所以 awk 脚本没有 FILE-A 中那么多行进行比较,并且可以在读取 FILE-B 时循环遍历这些行,而不是在读取 FILE-A 时循环遍历 FILE-B 行,因此能够只为 FILE-B 的每一行打开/关闭 1 个输出文件,而不是为 FILE-B 的每一行一次打开/关闭 1 个输出文件 * FILE-A 中与其匹配的每一行,以避免潜在的“打开太多”文件”错误。
$ cat tst.sh
#!/usr/bin/env bash
grep -F -f 'FILE-B' 'FILE-A' |
awk '
NR==FNR{ lines[++numLines]=$0; next }
{
close(out)
out = $0 ".txt"
for (i=1; i<=numLines; i++) {
line = lines[i]
if (index(line,$0)) {
print line > out
}
}
}
' - 'FILE-B'
$ ./tst.sh
$ head -100 *.txt
==> 1.txt <==
123
1239870
41967849
910
==> 2.txt <==
123
1239870
2349878
39742366876
2378
6723
==> 23.txt <==
123
1239870
2349878
39742366876
2378
6723
==> 78.txt <==
45678
2349878
41967849
789
2378