在单个文件中搜索单词非常简单:
grep stuff file.txt
但是我有很多文件,每个文件都是files.txt
中的一行,我想要找到很多单词,每一行都是words.txt
中的一行。输出应该是一个文件,每行a => b
a
是words.txt
中的行号,b
是files.txt
中的行号。
我需要在OSX上运行它,所以最好在shell中使用简单的东西,但任何其他语言都可以。我自己对shell脚本没有多少经验,而且我更习惯于对字符串搜索没用的语言(即C - 我猜Perl或Python可能会有所帮助,但我没有使用它们)。
答案 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
,则可以使用perl
,python
或ruby
。
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代码那样简短或可读。