在多个文件中搜索文本文件中的单词列表

时间:2018-04-06 03:07:52

标签: linux grep

我需要查看大量的文本文件,并列出包含其他文本文件中列出的所有单词的文本。

我只需要列出包含所有单词的文件。它不必按任何特定顺序排列。我曾尝试使用各种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 }' {} \;

但是我有很多单词并且不切实际。

谢谢。

3 个答案:

答案 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}的首位,这样您就可以尽快从检查中删除尽可能多的文件。