我正在编写一个脚本来在文件中进行字符串替换,我将从配置文件中读取变量,值和文件并进行字符串替换。
这是我做字符串替换的逻辑。
sub expansion($$$){
my $f = shift(@_) ; # file Name
my $vname = shift(@_) ; # variable name for pattern match
my $value = shift(@_) ; # value to replace
my $n = "$f".".new";
open ( O, "<$f") or print( "Can't open $f file: $!");
open ( N ,">$n" ) or print( "Can't open $n file: $!");
while (<O>)
{
$_ =~ s/$vname/$value/g; #check for pattern
print N "$_" ;
}
close (O);
close (N);
}
在我的逻辑中,我从输入文件($ f)逐行读取模式并写入新文件($ n)。
当我尝试执行相同的操作时,有没有办法在原始文件中替换原始文件,而不是写入新文件,只有空文件没有内容。
答案 0 :(得分:2)
不要。从不, 1 。你不敢,甚至不想,不要使用子程序原型。它被严重破坏(也就是说,它没有按照你的想法做到)并且是dangerous。
现在,我们已经解决了这个问题:
是的,你可以做你想做的事。您可以使用模式<+
open将文件作为可读写文件。到目前为止,非常好。
但是,由于缓冲,您无法使用标准的读写方法来读取和写入文件。相反,您需要使用sysread和syswrite。
然后,您需要做的是阅读行,使用sysseek返回到您阅读的位置的开头,然后写入该位置。
这不仅非常复杂,而且充满了危险。我们举一个简单的例子。我有一个文档,我想用直引号替换我的卷引号。
$line =~ s/“|”/"/g;
那应该有用。我正在用另一个角色替换一个角色。怎么可能出错?
如果这是一个UTF-8文件(默认情况下Mac和Linux系统使用),那些引号是双字节字符,而直引号是单字节字符。我会写回一条比我读入的行更短的行。我的缓冲区将会关闭。
回到以千字节为单位测量计算机内存和存储的日子,以及像卷到卷磁带这样的串行设备,这种类型的操作非常普遍。然而,在这个存储空间庞大的时代,这种复杂性和容易出错的过程根本不值得。坚持从一个文件读取,并写入另一个文件。然后使用unlink
和rename
删除原始文件,并将副本重命名为原始名称。
更多指示:
如果无法打开文件,请不要print
。使用die
。否则,您的程序将继续轻快地意识到它无法正常工作。更好的是,使用编译指示use autodie;,您不必担心测试读/写是否失败。
将标量用于文件句柄。
而不是
open OUT, ">my_file.txt";
使用
open my $out_fh, ">my_file.txt";
使用
open my $out_fh, ">", "my_file.txt";
use strict;
和use warnings;
。事实上,你的Perl语法有点古老。你需要在Modern Perl上找一本书。 Perl最初是用hack语言编写的,用来取代shell和awk编程。但是,Perl已经演变成一种完整的语言,可以处理复杂的数据类型,面向对象和大型项目。学习Perl的现代语法将帮助您找到错误,并成为更好的开发人员。
1。像所有规则一样,这可以被打破,但前提是你清楚而仔细地了解正在发生的事情。这就像那些说“不要在家里这样做的节目。我们是专业人士。”
答案 1 :(得分:0)
sub inplace_expansion($$$){
my $f = shift(@_) ; # file Name
my $vname = shift(@_) ; # variable name for pattern match
my $value = shift(@_) ; # value to replace
local @ARGV = ( $f );
local $^I = '';
while (<>)
{
s/\Q$vname/$value/g; #check for pattern
print;
}
}
或者,我的偏好会更接近于此(基本上相当于,主要在格式化,变量名称等方面进行更改):
use English;
sub inplace_expansion {
my ( $filename, $pattern, $replacement ) = @_;
local @ARGV = ( $filename ),
$INPLACE_EDIT = '';
while ( <> ) {
s/\Q$pattern/$replacement/g;
print;
}
}
local
的技巧基本上模拟了一个命令行脚本(就像用perl -e
运行一样);有关详细信息,请参阅perldoc perlrun
。有关$^I
(又名$INPLACE_EDIT
)的更多信息,请参阅perldoc perlvar
。
(对于\Q
的商家(在s//
表达式中),请参阅perldoc -f quotemeta
。这与您的问题无关,但很有用。另请注意传递正则表达式模式在变量周围 - 而不是,例如,仅使用文字正则表达式 - 可能容易受到注入攻击; Perl的内置taint mode在这里很有用。)