当前,我正在使用以下代码来查找替换字符串的字符串,并将其打印到输出文件中,其名称与输入文件中的名称相同,但位于替换的文件夹中
use Tie::File;
@files = <*>;
foreach $file (@files) {
my $filename = $file;
open(my $fh, '<:encoding(UTF-8)', $filename) or die "Could not open file '$filename' $!";
open(NEWFILE,"> ./replaced/$filename");
while(my $variable=<$fh>){
s/Insertstoredprocedure ( / Insertstoredprocedure('$filename',/g;
s/SuccessSp()/SuccessSp()('$filename')/g;
print NEWFILE "$variable";
print "done\n";
}
}
此脚本旨在替换所有内容,并将更改后的文件放入替换文件夹...。此操作不起作用,这会产生错误...我如何替换和打印其中的所有文件当前目录..
答案 0 :(得分:1)
直接错误和危险信号:
一旦您分配了while ($variable = <$fh>)
,$_
就不会设置为<$fh>
所读取的内容;保留原样(此处未定义);因此,与之匹配的正则表达式(默认情况下)将无法运行
要转义的正则表达式中需要将原义字符匹配的括号
该代码处理当前目录<*>
中的所有文件-在此代码中,该文件本身也可能包含脚本本身,并且没有保护或检查内容
我假设使用./replaced/
是指replaced/
在脚本所在的目录中,而不是在当前工作目录中(如pwd
);这些通常是不一样的。请澄清。
已更正,但有其他更改
use warnings;
use strict;
use feature qw(say);
use FindBin qw($RealBin);
use open ':std', ':encoding(UTF-8)';
my @files = grep { -f } @ARGV; # add further checks of user input
my $outdir = "$RealBin/replaced";
mkdir $outdir if not -d $outdir; # or use File::Path
foreach my $file (@files) {
my $fout = "$outdir/$file";
open my $fh, '<', $file or die "Can't open $file: $!";
open my $fh_out, '>', $fout or die "Can't open $fout: $!";
while (my $line = <$fh>) {
$line =~ s/Insertstoredprocedure \( / Insertstoredprocedure('$file',/g;
$line =~ s/SuccessSp\(\)/SuccessSp()('$file')/g;
print $fh_out $line;
}
say "done, $file --> $fout";
}
对问题代码的评论
始终使用use warnings;
和use strict;
<*>
从当前目录读取所有条目,这带来了一些棘手的问题;其中之一可能包括脚本本身。更重要的是,通过这种方式,可以将脚本与要处理的数据固定在一起。为什么不接受用户输入呢?我将其更改为使用在命令行上提交的文件名(大概是文件名)。然后在Linux上,您可以将脚本调用为
script.pl *.ext
如果必须,您仍然可以使用script.pl *
,但随后需要进行更多检查,尤其是确保跳过脚本本身(如果从其目录运行)。例如参见this post
始终检查输入是否适当。在这种情况下,您至少可以确保仅处理纯文件。我只是使用-f
filetest operator进行过滤,但另一个选择是将输入内容提交后再进行检查,以便您可以告知用户输入不足的情况
我认为不需要引入$filename
;只需使用topicalizer $file
如果您使用UTF8,最好使用open pragma;然后所有文件和流都得到照顾
对所有内容都使用词汇文件句柄,因此也要编写文件
从文件中读取一行时,为什么不将其命名为$line
?代码中的“ $variable
”是如此通用,以至于无法提供关于该变量是什么的任何线索
一旦您在while
条件下分配了一个命名变量,那么$_
不会设置为读取的内容;只有while (<$fh>)
会发生这种情况。在这段代码中,它在循环体内是未定义的。因此,在正则表达式中,您需要使用 that 变量,将 行分配给该变量(而不是将其保留为默认$_
)
如果要将正则表达式中具有特殊含义的字符作为文字字符进行匹配,则必须转义这些字符,并且括号就是其中之一。有多种方法可以实现,我使用您的文本并直接使用\
进行转义(无需在替换部分进行转义)
原则上,使用qr
operator将模式定义为单独的变量是一个好主意。然后,您可以使用quotemeta
我无法知道您的(已更正的)正则表达式是否达到了预期的目的,因此我只能解决明显的错误。请显示数据样本和所需的输出。
答案 1 :(得分:0)
请尝试以下方法吗?我假设在当前工作目录中找到了“已替换”。
use strict;
use warnings;
use Tie::File;
use English qw(-no_match_vars);
my @files = grep {-f} <*>;
-d './replaced/' or mkdir './replaced/';
foreach my $file (@files) {
open my $fh, '<:encoding(UTF-8)', $file
or die "Could not open file '$file': $OS_ERROR";
open my $newfh, '>', "./replaced/$file"
or die "Could not create new file './replaced/$file': $OS_ERROR";
while (<$fh>) {
s/Insertstoredprocedure\s*\(/Insertstoredprocedure('$file'/g;
s/SuccessSp\s*\(/SuccessSp('$file'/g;
print {$newfh} $_;
}
close $fh or die $OS_ERROR;
close $newfh or die $OS_ERROR;
print 'DONE with file: '.$file."\n";
}
强制性更改:
<*>
,以便我们丢弃目录。如果没有,尝试打开目录时会出现权限错误\(
$_
变量而不是$variable
。现在,它始终可以与$_
建议的更改:
use strict
和use warnings
(非常推荐)$!
用作$OS_ERROR
my
添加到foreach的变量open my $newfh, '>', ...
的3个参数