我有一个包含超过百个单列条目的文件。我需要将这些条目中的每一个搜索到一个包含多列和超过一千个条目的文件中,并且需要一个输出文件。我试过这些代码:
#!/usr/bin/perl -w
use strict;
use warnings;
print "Enter the input file name:";
my $inputfile = <STDIN>;
chomp($inputfile);
print "\nEnter the search file name:";
my $searchfile=<STDIN>;
chomp($searchfile);
open (INPUTFILE, $inputfile) || die;
open (SEARCHFILE, $searchfile) || die;
open (OUT, ">write.txt") || die;
while (my $line=<SEARCHFILE>){
while (<INPUTFILE>) {
if (/$line/){
print OUT $_;
}
}
}
close (INPUTFILE) || die;
close (SEARCHFILE) || die;
close (OUT) || die;
输出文件只有一行。它已将搜索文件中的术语搜索到输入文件中,但仅限于第一个术语,而不是全部。请帮忙!
答案 0 :(得分:6)
当您在内循环中阅读INPUTFILE
时,它会在第一轮SEARCHFILE
期间读到最后。因为它没有重置,所以文件句柄用完了并且将始终返回eof
。
如果有数百行,但不是几万,您可以先轻松地将其读入数组,然后将其用于查找。它是单列的事实使这非常容易。 请注意,这比下的替代解决方案效率低。
chomp( my @needles = <SEARCHFILE> );
while (<INPUTFILE>) {
foreach my $needle (@needles) {
print OUT $_ if m/\Q$needle\E/; # \Q end \E quote regex meta chars
}
}
或者你也可以构建一个匹配所有字符串的大型查找正则表达式。这可能比为每一行迭代数组要快。
# open ...
chomp( my @needles = <SEARCHFILE> );
my $lookup = join '|', map quotemeta, @needles;
my $lookup_regex = qr/$lookup/; # possibly with /i?
while (my $line = <INPUTFILE>) {
print OUT $line if $line =~ $lookup_regex;
}
quotemeta
负责处理包含/
或|
甚至.
等正则表达式字符的字符串。这与上面使用\Q
和\E
相同。
请同时使用三参数打开和命名文件句柄。
open my $fh_searchfile, '<', $searchfile or die $!;
open my $fh_inputfile, '<', $inputfile or die $!;
open my $fh_out, '>', 'write.txt' or die $!;
chomp( my @needles = <$fh_searchfile> );
# ...
三参数打开非常重要,因为您正在接收用户输入并直接将其用作文件名。恶意用户可能会输入类似| rm -rf *
的内容,这会打开一个管道,删除我的所有文件而不询问程序。哎呀。但是如果在其自己的参数中明确指定'<'
read open方法,则在第三个参数中忽略方法字符。
如名称所示,词汇文件句柄$fh
是词法,而INPUTFILE
是GLOB,它使其成为全局的。如果你只有这个脚本而没有模块,那就没那么糟了,但是一旦你处理不同的软件包就会出现问题,因为那些是超级全局的,程序的每个部分都会看到它们。这可能会导致名称冲突和奇怪的事情发生。