[英]Modify a string in a file with perl
我有一个文件d00.dat,我需要将字符串d01更改为d02 ...使用以下代码,它将在控制台中打印修改内容,但它们在文件d00.dat中没有更改...我该如何更改去做?
my $line = 0;
my $filename = "d00.dat";
open(my $fh, '<', $filename) || die "file could not open $! \n";
while( $line = <$fh>) {
if( $line =~ s/d01/d02/g ){
print "$line\n";
}
最简单,最快的解决方案是将文件读入内存,进行更改,然后将更改写回到文件中。
my $qfn = "d00.dat";
my $file;
{
open(my $fh, '<', $qfn)
or die("Can't open \"$qfn\": $!\n");
local $/;
$file = <$fh>;
}
$file =~ s/d01/d02/g;
{
open(my $fh, '>', $qfn)
or die("Can't create \"$qfn\": $!\n");
print($fh $file);
}
作为单线:
perl -i -pe's/d01/d02/g' d00.dat
如果您只想更改这些位置,则不必-不得不替换整个文件。 †
您可以将包括更改在内的每一行打印到另一个文件,然后将其复制。 许多工具都以这种方式工作。 或者,您可以读取所有行,对其进行适当更改,然后覆盖文件。
my $filename = "d00.dat";
open(my $fh, '<', $filename) || die "file could not open $! \n";
my @new_lines = map { s/d01/d02/g; $_ } <$fh>;
close $fh;
open(my $fh_out, '>', $filename) || die "file could not open $! \n";
print $fh_out $_ for @new_lines;
close $fh_out;
由于open
将关闭文件句柄(如果已打开),您也可以执行
open my $fh, '<', $filename or die "Can't open $filename: $!";
my @new_lines = map { s/d01/d02/gr } <$fh>;
open $fh, '>', $filename or die "Can't open $filename: $!";
print $fh $_ for @new_lines;
close $fh;
我在其中删除parens并将其更改为or
,然后将$filename
添加到错误消息中。 我还在正则表达式中使用了/r
修饰符(“ 非破坏性替换 ”),通过它返回更改后的字符串-正是该map
所需的字符串,因此现在我们不需要在末尾使用单独的$_
块。
问题中出现的die
消息末尾的换行符有一个微妙的结果:它抑制了有关发出die
的行号的信息。 虽然这有时期望,在大多数情况下,它是不是在这里我们当然希望看到调用,它失败的行号! 因此,我在die
的消息中删除了该额外的换行符。
†文件是字节序列。 因此,如果我们想用yes
代替一个nope
...当我们替换了前三个字符时,最后一个字符e
会发生什么? 我们必须按照原始的nope
移动文件的其余部分,以覆盖e
,因此现在遵循yes
。 因此,我们需要覆盖文件的其余部分,实际上,仅替换整个文件要容易得多。
如果我们想用yeah
代替nope
...好吧,现在是4比4,实际上我们可以覆盖这4个字符。 但是,这种情况很少发生,并且执行起来更加复杂。
当问题要求用d02
替换d01
,我想这是一个示例,而实际上字符串的长度通常不相同。 即使他们正在...替换文件也更加容易和安全,并且很可能不会发现效率损失。
Perl有一个开关可以就地修改文件。 我认为这就是您要寻找的:
perl -i.bak -p -e 's/d01/d02/g;' d00.dat
这将
d00.dat
重命名为d00.dat.bak
d00.dat.bak
d02
替换每次出现的d01
d00.dat
说明:
-i
就地编辑文件,如果给定了一些后缀,则可以选择进行备份。 例如, -i.bak
将创建$file.bak
, -i.before
将创建$file.before
等。如果没有后缀(仅-i
),将没有备份,因此请考虑这样做是危险的。
-p
放置像
while(<>) { # your code print; }
在这种情况下( s/…/…/g;
)
-e
仅仅表示“执行以下语句” 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.