如何从文件中列出的文件中的文件中搜索单词?

时间:2011-03-04 06:37:08

标签: python perl macos shell

在单个文件中搜索单词非常简单:

grep stuff file.txt

但是我有很多文件,每个文件都是files.txt中的一行,我想要找到很多单词,每一行都是words.txt中的一行。输出应该是一个文件,每行a => b awords.txt中的行号,bfiles.txt中的行号。

我需要在OSX上运行它,所以最好在shell中使用简单的东西,但任何其他语言都可以。我自己对shell脚本没有多少经验,而且我更习惯于对字符串搜索没用的语言(即C - 我猜Perl或Python可能会有所帮助,但我没有使用它们)。

8 个答案:

答案 0 :(得分:1)

首先,学习指定感兴趣的文件。在一个目录或多个目录中? Unix find实用程序会这样做。

在Bash提示符下:

$ cd [the root directory where your files are]
$ find . -name "*.txt"

你没有说,但可以说这些文件可用“星点点什么”来描述,然后找到会找到这些文件。

接下来,将文件名称传递给您要对它们执行的操作:

$ find . -name "*.txt" -print0 | xargs -0 egrep 'stuff'

对于搜索模式为egrep

的每个文件,都会运行stuff

Google find加上xargs数千个例子。一旦你习惯找到文件 - 改写你的问题,这样你就可以更明显地想要对他们做些什么了。然后我可以帮你用Perl来做。

答案 1 :(得分:1)

你可能会更快,更Pythonic,更容易理解:

with open("words.txt") as words:
    wlist=[(ln,word.strip()) for ln,word in enumerate(words,1)]

with open("files.txt") as files:
    flist=[(ln,file.strip()) for ln,file in enumerate(files,1)]

for filenum, filename in flist:
    with open(filename) as fdata:
        for fln,line in enumerate(fdata,1):
            for wln, word in wlist:
                if word in line:
                    print "%d => %d" % (wln, fln)

答案 2 :(得分:1)

这是awk的两个部分: 1.扫描files.txt中的每个文件,并将单词编号映射到文件名 2.将文件名映射到files.txt

中的行号
awk '
  NR == FNR {word[$1] = NR; next}
  {for (i=1; i<=NF; i++) {if ($i in word) {print word[$i] " => " FILENAME; break}}}
' words.txt $(<files.txt) | 
sort -u |
awk '
  NR == FNR {filenum[$1] = NR; next}
  {$3 = filenum[$3]; print}
' files.txt -

答案 3 :(得分:0)

这可以做你想做的事情,但唯一的事情就是打印出匹配的单词,而只打印出匹配的行,文件名和行号。但是,如果您在grep上使用--color=auto,它会使用您在${GREP_COLOR}中设置的任何内容突出显示匹配的字词,默认为红色。

cat files.txt | xargs grep -nf words.txt --color=auto

此命令将逐行转储files.txt的所有内容,并将文件名传递给grep,后者将在文件中搜索words.txt中匹配的每个单词。与files.txt类似,words.txt应该是您希望用换行符分隔的所有搜索字词。

如果您的grep是使用perl正则表达式引擎构建的,那么,如果您将-P选项传递给grep,则可以使用Perl正则表达式:

grep -Pnf words.txt --color=auto

希望这有帮助。

更新:起初,我不太确定@Zeophlite在问什么,但在他发布他的例子之后,我看到了他想要的东西。这是他想要做的python实现:

from contextlib import nested


def search_file(line_num, filename):
    with nested(open(filename), open('words.txt')) as managers:
        open_filename, word_file = managers
        for line in open_filename:
            for wordfile_line_number, word in enumerate(word_file, 1):
                if word.strip() in line:
                    print "%s => %s" % (line_num, wordfile_line_number)


with open('files.txt') as filenames_file:
    for filenames_line_number, fname in enumerate(filenames_file, 1):
        search_file(filenames_line_number, fname.strip())

答案 4 :(得分:0)

python中的以下脚本可以做到这一点。这是我第一次尝试python,所以我很感激任何评论

flist = open('files.txt')

filenum = 0
for filename in flist:
    filenum = filenum + 1
    filenamey = filename.strip()
    filedata = open(filenamey)
    for fline in filedata:
        wordnum = 0
        wlist = open('words.txt')
        for word in wlist:
            wordnum = wordnum + 1
            sword = word.strip()
            if sword in fline:
                s = repr(filenum) + ' => ' + repr(wordnum)
                print s

答案 5 :(得分:0)

回答您的要求

您的代码:

flist = open('files.txt') 

filenum = 0 
for filename in flist: 
    filenum = filenum + 1 
    filenamey = filename.strip() 
    filedata = open(filenamey) 
    for fline in filedata: 
        wordnum = 0 
        wlist = open('words.txt') 
        for word in wlist: 
            wordnum = wordnum + 1 
            sword = word.strip() 
            if sword in fline: 
                s = repr(filenum) + ' => ' + repr(wordnum) 
                print s 

您打开'files.txt'但不要关闭它。 with open('files.txt') as flist:更可取,因为它在文本上更清晰,并且可以单独关闭。

使用filenum = filenum + 1而不是enumerate() 从现在开始,你绝不能忘记enumerate(),因为它是一个非常有用的功能。它的工作速度非常快。

fline 对于行的迭代器IMO来说不是一个好名字; 不是很好吗?

指令wlist = open('words.txt')不是很好:它不仅针对每个打开的文件执行,而且每次执行分析时都会执行。 此外,每次重复 wlist 时,也就是说在每一行,都会对 wlist 中列出的名称进行处理。你必须将这种处理方法排除在所有迭代之外。

wordnum 只是 wlist word 的索引。您可以再次使用enumerate()或只使用索引循环并使用wlist[i]代替 word

每当 wlist 出现在该行中时,您就会

print repr(filenum) + ' => ' + repr(wordnum) 

最好做print repr(filenum) + ' => ' + repr(all_wordnum),其中all_wordnum将是一行中找到的所有的列表

您将单词列表保存在文件中。你最好将这些单词的列表序列化。查看模块 pickle pickle

在录制结果方面还有一些改进。因为执行指令

print repr(filenum) + ' => ' + repr(wordnum)

每次都不是一个好习惯。如果你想在一个文件中记录它是一样的:你不能重复订购write()更好的是列出所有结果列表,并在流程结束时打印或记录,制作"\n".join(list)或类似的东西

答案 6 :(得分:0)

在纯shell中完成它,我很接近:

$ grep -n $(tr '\n' '|' < words.txt | sed 's/|$//') $(cat files.txt)

(试图找出如何删除$(cat files.txt)但不能删除

这会打印出每个文件中的单词,并打印出它们出现的行,但不打印出该单词所在的words.txt行。

可能有一些非常丑陋(如果你认为这不够丑陋)我可以做的事情,但你真正的答案是使用更高级别的语言。 awk解决方案是shellish,因为大多数人现在认为awk只是Unix环境的一部分。但是,如果您使用的是awk,则可以使用perlpythonruby

awk的唯一优势是,即使创建发行版的用户不包含任何开发包,它也会自动包含在Linux / Unix发行版中。这很罕见,但它确实发生了。

答案 7 :(得分:0)

sh答案,假设单词或文件名不包含任何shell元字符,例如空格:

nw=0; while read w; do nw=`expr $nw + 1`; nf=0; { while read f; do nf=`expr $nf + 1`; fgrep -n $w $f | sed 's/:.*//' | while read n; do echo $nw =\> $nf; done; done < /tmp/files.txt;}; done < /tmp/words.txt

但我更喜欢Perl这种事情。 除非你使用IO::All,否则Perl脚本不会像carrrot-top的Python代码那样简短或可读。