我经常用
perl -pi -w -e 's/search/replace/g;' [filelist]
在 [filelist] 的所有文件中用“replace”替换每个出现的“search”。不幸的是,所有文件似乎都获得了更新的时间戳。即使“搜索”没有出现在文件中。我可以改变这是一个简单的方法吗?
不容易,不。所发生的一切是 perl 正在用通过正则表达式的结果覆盖文件。
您可以使用更长的程序来做到这一点,但没有简单的标志可以阻止这种行为。
-i
松散地:
rename($ARGV, "$ARGV$^I") or die $! if length $^I;
open(*ARGV, '<', "$ARGV$^I") or die $!;
open(*STDOUT, '>', $ARGV) or die $!;
如您所见,它总是立即替换现有文件。这就是所有打印件 ( -p
) 发送其输出的地方。
两种选择:
使用临时文件。
perl -e'
$temp_qfn = "temp";
open(my $fh_out, ">", $temp_qfn) or die $!;
my $save;
while (<>) {
$save = 1 if s/search/replace/g;
print($fh_out $_);
} continue {
if (eof) { # Not eof()!
close($fh_out);
rename($temp_qfn, $ARGV) if $save;
$save = 0;
open(my $fh_out, ">", $temp_qfn) or die $!;
}
}
close($fh_out);
unlink($temp_qfn);
' file ...
将整个文件加载到内存中。
perl -0777ne'
if (s/search/replace/g) {
open(my $fh_out, ">", $ARGV) or die $!;
print($fh_out $_);
}
' file ...
(以上两者都有各种可解决的错误处理问题。-i
有一些相同的问题。)
-i[*extension*]
指定由“
<>
”构造处理的文件将被就地编辑。它通过重命名输入文件、按原始名称打开输出文件并选择该输出文件作为print()
语句的默认文件来完成此操作。扩展名(如果提供)用于修改旧文件的名称以制作备份副本,遵循以下规则:如果未提供扩展名,则不进行备份并覆盖当前文件。
强调我的。
为了解决这个问题,您需要编写一个程序,为 中的每个文件打开一个临时文件@ARGV
,从原始文件中读取,进行替换,将行写入临时文件,并跟踪是否有任何替换更改了原线。当到达文件末尾时,如果任何s///
调用导致更改,它会将临时文件重命名为原始文件。eof对此以及File::Temp模块都很有用。