给定示例文件
file1.txt
word1
word2
word4
word5
file2.txt
word1
word2
word3
word4
file3.txt
word2
word3
word4
file4.txt
word0
word1
word2
word3
word4
file5.txt
word0
word1
word2
word3
word4
word5
这个老式的 awk/shell 代码
#!/bin/bash
wordList="$1"
shift
awk -v wdListFile="$wordList" '
BEGIN{
dbg=0
while(getline < wdListFile > 0 ) {
words[$0]=$0
flags[$0]=0
numFlags++
}
}
{
if (dbg) { print "#dbg: myFile=" myFile " FILENAME=" FILENAME }
if (myFile != FILENAME) {
# a minor cost of extra reset on the first itteration in the run
if (dbg) { print "#dbg: inside flags reset" }
for (flg in flags) {
flags[flg]=0
}
}
for (i=1; i<=NF; i++) {
if (dbg) { print "#dbg: $i="$i }
if ($i in words) {
flags[$i]++
}
}
matchedCnt=0
for (f in flags) {
if (dbg) { print "#dbg: flags["f"]="flags[f] }
if (flags[f] > 0 ) {
matchedCnt++
if (dbg) { print "#dbg: incremeted matchedCnt to " matchedCnt}
}
}
if (dbg) {print "#dbg: Testing matchedCnt=" matchedCnt "==numFlags=" numFlags}
if (matchedCnt == numFlags) {
if (dbg) { print "All words found in "FILENAME "matchedCnt=" matchedCnt " numFlags=" numFlags}
print FILENAME
nextfile
}
myFile=FILENAME
if (dbg) { print "#dbg: myFile NOW=" myFile }
}' $@
从命令行运行
./genGrep.sh wd.lst file*.txt
产生以下输出
file2.txt
file4.txt
file5.txt
只有一次,使脚本可执行
chmod 755 ./genGrep.sh
我建议使用名称中的dbg 制作此文件的副本,然后获取原始副本并删除所有带有dbg 的行。这样,如果您需要,您将拥有一个 dbg 版本,但 dbg 行增加了大约 20% 的代码阅读量。
请注意,您可以通过设置dbg=1 来打开所有dbging,或者您可以通过添加! 字符来打开各个行,即if (! dbg) { ...}。
如果由于某种原因您在非常旧的 Unix 硬件上运行,nextfile 命令可能不起作用。查看您的系统是否有可用的gawk,或者安装它。
如果不是内置的,我认为获取 nextfile 行为有一个技巧,但我现在不想花时间研究它。
请注意,使用flags[] 数组、matchedCnt 变量和内置awk 函数nextfile 旨在在找到所有单词后停止在文件中搜索。
您还可以添加一个参数来表示“如果 n 百分比匹配,则打印文件名”,但这会附带咨询费率。
如果您不理解精简后的 awk 代码(删除 dbg 部分),请在提问之前按照自己的方式联系 Grymoire's Awk Tutorial。
管理数千个文件(如您所说)是一个单独的问题。但是为了让事情顺利进行,我会打电话给genGrep.sh wd.lst A* ; genGrep.sh wd.lst B*; ... 并希望它能奏效。问题是命令行有一个可以在文件名列表中一次处理的字符的限制。因此,如果A* 扩展到 10 亿个字符,那么您必须找到一种方法将行大小分解为 shell 可以处理的内容。
通常,这是通过xargs 解决的,所以
find /path/to/files -name 'file*.txt' | xargs -I {} ./genGrep.sh wd.lst {}
将找到您通过通配符指定的所有文件,如您作为find 的第一个参数列出的一个或多个/path/to/file。
所有匹配的文件都通过管道发送到xargs,它从列表中读取一个命令调用可以处理的所有文件,并继续循环(对您不可见),直到所有文件都已处理完毕。
如果您的计算机上有额外的“核心”可用,xargs 有额外的选项允许运行./genGrep.sh 的多个副本。我不想深入探讨,因为我不知道其余部分是否真的适用于您的实际使用。
IHTH