我需要查看大量的文本文件,并列出包含其他文本文件中列出的所有单词的文本。
我只需要列出包含所有单词的文件。它不必按任何特定顺序排列。我曾尝试使用各种grep命令,但它只输出包含任何单词的文件,而不是所有单词。使用包含单词列表的txt文件作为搜索grep是理想的。
尝试
grep -Ffw word_list.txt /*.fas
find . -exec grep "word_list.txt" '{}' \; -print
我找到了使用多种管道的解决方案,例如
awk "/word1/&&/word2/&&/word3/" ./*.txt
find . -path '*.txt' -prune -o -type f -exec gawk '/word1/{a=1}/word2/{b=1}/word3/{c=1}END{ if (a && b && c) print FILENAME }' {} \;
但是我有很多单词并且不切实际。
谢谢。
答案 0 :(得分:1)
这有点黑客,因为没有直接的方法在grep中做AND ..我们可以使用grep -E选项来模拟AND。
grep -H -E "word1" *.txt| grep -H -E "word2" *.txt|grep -H -E "word3" *.txt | grep -H -E "word4" *.txt| cut -d: -f1
-H => --with-filename
-E => --extended-regexp
cut -d: -f1 => to print only the file name.
答案 1 :(得分:1)
给定样本文件
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
来切换所有dbg=1
或者您可以通过添加!
字符来启用各行,即if (! dbg) { ...}
。
如果由于某种原因您在非常旧的Unix硬件上运行,nextfile
命令可能无效。查看您的系统是否有gawk
可用,或者安装它。
我认为如果没有内置的话,有一个获取nextfile行为的技巧,但我现在不想花时间研究它。
请注意,flags[]
数组,matchedCnt
变量和内置awk
函数nextfile
的使用旨在一旦找到所有单词后停止在文件中搜索
您还可以添加一个参数来说明&#34;如果n%匹配,则打印文件名&#34;,但附带咨询费率。
如果您不理解已删除的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 {}
将查找您通过通配符指定的所有文件,从1个或多个/path/to/file
列出find
的第一个参数。
所有匹配的文件都通过管道发送到xargs
,它从一个命令调用可以处理的列表中读取所有文件,并继续循环(对您不可见),直到所有文件都被处理完毕。
xargs
有额外的选项允许运行多个./genGrep.sh
副本,如果你有额外的&#34;核心&#34;可在您的计算机上使用我不想深入了解这一点,因为我不知道其余部分是否真的会在您的实际使用中发挥作用。
IHTH
答案 2 :(得分:0)
尝试类似:
WORD_LIST=file_with_words.txt
FILES_LIST=file_with_files_to_search.txt
RESULT=file_with_files_containing_all_words.txt
# Generate a list of files to search and store as provisional result
# You can use find, ls, or any other way you find useful
find . > ${RESULT}
# Now perform the search for every word
for WORD in $(<${WORD_LIST}); do
# Remove any previous file list
rm -f ${FILES_LIST}
# Set the provisional result as the new starting point
mv ${RESULT} ${FILES_LIST}
# Do a grep on this file list and keep only the files that
# contain this particular word (and all the previous ones)
cat ${FILES_LIST} | xargs grep -l > $RESULT
done
# Clean up temporary files
rm -f ${FILES_LIST}
此时你应该在$ RESULTS中包含$ {WORD_LIST}中包含所有单词的文件列表。
此操作成本很高,因为您必须一次又一次地读取所有(仍然)候选文件中的每个单词,因此请尝试将较不频繁的单词放在$ {WORD_LIST}的首位,这样您就可以尽快从检查中删除尽可能多的文件。