我有一个perl脚本问题,它让我心烦意乱。我编写了一个使用File :: Find模块的脚本,该模块应该从给定的参数目录开始递归地行走,并对已经找到的每个* .txt文件执行一个函数。我简化了这个问题,只显示了主要部分。
为了让它运行并重现我的问题,我们必须创建一个包含两个文件的目录:
fist.txt
和second.txt
每个只有两条线:
cat fist.txt
:
AAA
BBB
cat second.txt
:
AAA
BBB
#!/usr/bin/perl
use File::Find;
$ARGS_NUM = $#ARGV + 1;
if ($ARGS_NUM != 1) {
print "Add start directory as an argument!\n";
exit(-1);
}
my $DEST_DIR =$ARGV[0];
find(\&splitter, $DEST_DIR);
sub splitter {
if (-f $_ && /\.txt$/) {
$DOC_FILE_NAME = $_;
print "processing: $DOC_FILE_NAME\n";
open $DOC_FILE, "<"."$DOC_FILE_NAME" or die "Could not open $DOC_FiLE\n";
print "Entering first WHILE, DOC_FILE = $DOC_FILE\n";
$AAA_FOUND = 0;
$BBB_FOUND = 0;
while(<$DOC_FILE>) {
print "first_while\n";
if (m/^AAA$/i) {
print "FOUND: AAA in $DOC_FILE\n";
$AAA_FOUND = 1;
next;
}
if (m/^BBB$/i) {
print "FOUND: BBB in $DOC_FILE\n";
$BBB_FOUND = 1;
next;
}
}
#################### SECOND WHILE WCHICH FAILS.... #################
$/="";
seek $DOC_FILE,0,0;
$QQQ_FOUND = 0;
print "Entering second WHILE, DOC_FILE = $DOC_FILE\n";
while(<$DOC_FILE>) {
print "second_while\n";
s/\n//g; s/$/\n/; s/^\s*//;
if ($QQQ_FOUND == 1) {
$question_text = $_;
print "question_text = $question_text\n";
last;
}
if (m/^QQQ.*$/i) {
$QQQ_FOUND=1;
}
}
$/ = undef;
print "AAA = $AAA_FOUND\n";
print "BBB = $BBB_FOUND\n";
print "QQQ = $QQQ_FOUND\n";
close $DOC_FILE;
}
}
这是OUTPUT:
processing: first.txt
Entering first WHILE, DOC_FILE = GLOB(0x13087e0)
first_while
FOUND: AAA in GLOB(0x13087e0)
first_while
FOUND: BBB in GLOB(0x13087e0)
Entering second WHILE, DOC_FILE = GLOB(0x13087e0)
second_while
AAA = 1
BBB = 1
QQQ = 0
processing: second.txt
Entering first WHILE, DOC_FILE = GLOB(0x13087e0)
first_while
Entering second WHILE, DOC_FILE = GLOB(0x13087e0)
second_while
AAA = 0
BBB = 0
QQQ = 0
编辑: 正如您可以看到第二个循环未命中搜索值AAA和BBB。
答案 0 :(得分:4)
确实如此,因为您将$/
设置为undef
,这启用了slurp模式(意思是&#34;只需一次调用<>
即可读取整个文件)。 $/
的默认值不是undef
,而是"\n"
。
您应该只使用local $/;
而不是尝试手动重置它。
答案 1 :(得分:0)
很多人发现File::Find
很烦人。它根本不起作用。它破坏了良好的编程实践。
我发现使用它的最佳方法是在想要的子例程之外设置一个列表变量,然后使用它来保存符合条件的文件。然后,您可以返回常规程序进行实际工作:
my @file_list;
find ( &wanted, $DEST_DIR);
sub wanted {
next unless -f and /\.txt$/;
push @file_list, $File::Find::name;
}
# Now use @file_list to do what you need:
for my $file (@file_list) {
yadda, yadda, yadda
}
由于想要的功能要短得多,你可以在find
函数中组合想要的函数:
find (
sub {
next unless -f and /\.txt$/;
push @file_list, $File::Find::name;
},
$DEST_DIR
);