我的 perl 替换破折号模式清除了所有文件内容
Posted
技术标签:
【中文标题】我的 perl 替换破折号模式清除了所有文件内容【英文标题】:My perl replace dash pattern wipes out all file contents 【发布时间】:2022-01-16 17:48:12 【问题描述】:在下面的代码中,我试图用相应数量的空格替换“---- ------”模式。当我运行代码时,所有文件内容都被清除了。我不知道为什么。我在下面有要进行替换的示例文本。 我将不胜感激。
#!/usr/bin/perl -w
use strict;
use warnings;
use File::Path;
use File::Copy;
use feature 'unicode_strings';
use utf8;
my $IN;
my $dir;
opendir $dir, $Dirs[$mm] or die "opendir failed on $Dirs[$mm]: $! ($^E)";
while (my $file = readdir $dir) #reading input directory
next if -d $file;
if ($file =~ /Ranked/)
print "$file\n";
open ($IN, "+> $Dirs[$mm]/$file") or die "open '$file': failed $! ($^E)";
while (<$IN>)
s/---- ------/ /g;
print "$_\n";
close $dir;
exit;
END
Ranked Rainfall: Jun
********************
CHIPAT01 CHIPEP01 CHOMA001 ISOKA001 KABOMP01 KABWE001 KABWE002 KAFIRO01 KAFUE001 KALABO01 KAOMA001 KASAMA01 KASEMP01
Year Rnfl Year Rnfl Year Rnfl Year Rnfl Year Rnfl Year Rnfl Year Rnfl Year Rnfl Year Rnfl Year Rnfl Year Rnfl Year Rnfl Year Rnfl 1968 17.0 2003 13.2 2000 29.2 2004 3.1 1988 13.3 1988 2.8 ---- ------ 1967 2.8 1966 1.3 2009 2.3 1965 10.7 1968 11.9 1988 6.0 1983 5.8 2011 6.1 1966 14.0 2002 2.0 1965 9.4 1960 0.5 ---- ------ ---- ------ 1960 0.6 ---- ------ 2009 1.8 1952 0.8 1940 5.1 1974 4.6 1996 0.6 1997 4.5 ---- ------ 1966 2.3 1986 0.1 ---- ------ ---- ------ ---- ------ ---- ------ 1966 0.3 1936 0.3 1966 4.8 1960 3.3 2007 0.5 1988 4.0 ---- ------ Ave 0.5 Ave 0.1 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ Ave 0.2 1965 1.8 1999 0.3 2002 3.7 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ 1948 1.6 Ave 0.1 2003 3.6 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ 1971 1.0 ---- ------ 1955 3.3 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ 1978 0.9 ---- ------ 1976 2.5 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ 1961 0.5 ---- ------ 1975 1.6 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ 1946 0.5 ---- ------ 1978 1.6 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ 1967 0.5 ---- ------ 2011 1.4 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ Ave 0.4 ---- ------ 1960 1.3 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ 1964 0.3 ---- ------ 2009 1.0 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ 1996 0.6 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ 1969 0.6 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ Ave 0.5 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ 1958 0.5 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ 1979 0.3 ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------ ---- ------
【问题讨论】:
请阅读open 的文档,尤其是有关模式的文档。也许你打算open(my $in, '<', $fname) or die "Error message"
。以下 [webpage] 具有打开模式表,其中包含模式描述。以"+> $fname"
模式打开的文件会截断文件,然后允许写入它——你截断文件,然后才尝试写入它。
链接到webpage。
可以使用类似perl -pi.bak -e 's/-/ /g' some_file.dat
的命令对文件进行所需的操作
代码在当前条件下无法运行:Global symbol "@Dirs" requires explicit package name
,$mm
也是如此。
【参考方案1】:
同时读取和写入同一个文件需要小心。在这里,您正在使用+>
同时读取和写入$file
。但是,open
的文档警告说:
您可以在
>
或<
前面放置一个+
,表示您希望对文件具有读写权限;因此+<
几乎总是首选用于读/写更新——+>
模式会首先破坏文件
相反,您应该写入一个临时文件。完成写入后,您可以将原始文件替换为临时文件。要打开一个临时文件,您可以使用File::Temp
模块。要将原始文件替换为新文件,您可以使用File::Copy
模块中的move
。您的代码已更正:
use File::Temp qw(tempfile);
use File::Copy;
while (my $file=readdir $dir)
next if -d "$dir/$file";
if($file =~ /Ranked/)
print "$file\n";
my ($out_fh, $out_filename) = tempfile();
open (my $IN, "<", "$Dirs[$mm]/$file") or die "open '$file': failed $! ($^E)";
while( <$IN> )
s/---- ------/ /g;
print $out_fh $_;
close $out_fh;
copy($out_filename, "$Dirs[$mm]/$file");
请注意,在 copy
之前关闭 $out_fh
很重要。
小提示:
next if -d $file
应该是next if -d "$dir/$file"
。
您应该在尽可能窄的范围内声明您的变量。这意味着您应该使用open my $IN, ...
,而不是使用my $IN;
开始您的脚本,然后再使用open $IN, ...
。 my $dir
和 opendir
也一样。
替代解决方案:
Perl 具有用于就地文件编辑的内置机制,但它更适合单行而不是完整脚本。这是由-i
command-line switch 启用的,但如果需要也可以使用outside of one-liners。
一些 CPAN 包(例如 File::Inplace
可用于避免自己编写整个 tempfile
/move
样板。
【讨论】:
这很完美@Dada。非常感谢。只剩下一个问题了。之后留下的空白行,我想摆脱它们。我的代码中有 s/^\s+$//g,但它似乎不起作用。 该代码 (s/^\s+$//g) 确实有效。再次感谢。 @ZiloreMumba 完美。乐于助人:)以上是关于我的 perl 替换破折号模式清除了所有文件内容的主要内容,如果未能解决你的问题,请参考以下文章