我正在以附加模式打开文件。我需要替换文件中的第 2,3 和 4 行,然后我需要在文件末尾添加新数据。
我认为这是我在 Stack Overflow 上转发次数最多的常见问题解答。 perlfaq5 提供了以下问题的答案:如何在文件中更改、删除或插入一行,或附加到文件的开头?.
忘记附加模式的东西。这只会让你的生活变得更加艰难。
从文本文件中插入、更改或删除一行的基本思想包括读取并打印文件到您想要更改的位置,进行更改,然后读取并打印文件的其余部分。 Perl 不提供对行的随机访问(特别是因为记录输入分隔符
$/
是可变的),尽管像 Tie::File 这样的模块可以伪造它。
执行这些任务的 Perl 程序采用的基本形式是打开文件、打印其行,然后关闭文件:
open my $in, '<', $file or die "Can't read old file: $!";
open my $out, '>', "$file.new" or die "Can't write new file: $!";
while( <$in> )
{
print $out $_;
}
close $out;
在该基本表单中,添加需要插入、更改或删除行的部分。
要将行添加到开头,请在进入打印现有行的循环之前打印这些行。
open my $in, '<', $file or die "Can't read old file: $!";
open my $out, '>', "$file.new" or die "Can't write new file: $!";
print $out "# Add this line to the top\n"; # <--- HERE'S THE MAGIC
while( <$in> )
{
print $out $_;
}
close $out;
要更改现有行,请插入代码以修改 while 循环内的行。在这种情况下,代码找到“perl”的所有小写版本并将它们转为大写。每行都会发生这种情况,因此请确保您应该在每一行都执行此操作!
open my $in, '<', $file or die "Can't read old file: $!";
open my $out, '>', "$file.new" or die "Can't write new file: $!";
print $out "# Add this line to the top\n";
while( <$in> )
{
s/\b(perl)\b/Perl/g;
print $out $_;
}
close $out;
要仅更改特定行, 输入行号
$.
非常有用。首先阅读并打印直到您要更改的行。接下来,读取要更改的单行,更改它,然后打印它。之后,阅读其余行并打印它们:
while( <$in> ) # print the lines before the change
{
print $out $_;
last if $. == 4; # line number before change
}
my $line = <$in>;
$line =~ s/\b(perl)\b/Perl/g;
print $out $line;
while( <$in> ) # print the rest of the lines
{
print $out $_;
}
要跳行,请使用循环控件。本示例中的下一个会跳过注释行,最后一个一旦遇到
__END__
或 __DATA__
,就会停止所有处理。
while( <$in> )
{
next if /^\s+#/; # skip comment lines
last if /^__(END|DATA)__$/; # stop at end of code marker
print $out $_;
}
通过使用 next 跳过您不想在输出中显示的行,执行相同的操作来删除特定行。此示例每隔五行跳过一次:
while( <$in> )
{
next unless $. % 5;
print $out $_;
}
如果出于某种奇怪的原因,您确实想一次查看整个文件而不是逐行处理,您可以将其吞入其中(只要您可以将整个文件放入内存中!):
open my $in, '<', $file or die "Can't read old file: $!"
open my $out, '>', "$file.new" or die "Can't write new file: $!";
my @lines = do { local $/; <$in> }; # slurp!
# do your magic here
print $out @lines;
诸如 File::Slurp 和 Tie::File 之类的模块也可以提供帮助。但是,如果可以的话,请避免一次读取整个文件。在进程完成之前,Perl 不会将该内存返还给操作系统。
您还可以使用 Perl 语句就地修改文件。以下内容将 inFile.txt 中的所有 'Fred' 更改为 'Barney',并用新内容覆盖该文件。使用
-p
开关,Perl 会在您使用 -e
指定的代码周围包装一个 while 循环,并且 -i
打开就地编辑。当前行位于 $_
中。使用 -p
,Perl 在循环结束时自动打印 $_
的值。有关更多详细信息,请参阅 perlrun。
perl -pi -e 's/Fred/Barney/' inFile.txt
要备份 inFile.txt,请给
-i
添加文件扩展名:
perl -pi.bak -e 's/Fred/Barney/' inFile.txt
如果只更改第五行,可以添加测试检查
$.
,输入行号,然后仅在测试通过时执行操作:
perl -pi -e 's/Fred/Barney/ if $. == 5' inFile.txt
要在某一行之前添加行,您可以在 Perl 打印之前添加一行(或多行!)
$_
:
perl -pi -e 'print "Put before third line\n" if $. == 3' inFile.txt
您甚至可以在文件的开头添加一行,因为当前行打印在循环的末尾:
perl -pi -e 'print "Put before first line\n" if $. == 1' inFile.txt
要在文件中已有的一行之后插入一行,请使用
-n
开关。它就像 -p
一样,只是它不会在循环末尾打印 $_
,所以你必须自己做。在这种情况下,请先打印 $_
,然后打印要添加的行。
perl -ni -e 'print; print "Put after fifth line\n" if $. == 5' inFile.txt
要删除行,只打印您想要的行。
perl -ni -e 'print unless /d/' inFile.txt
... or ...
perl -pi -e 'next unless /d/' inFile.txt
您可以使用 Tie::File 来完成此操作。 (请注意,它必须重写整个文件才能替换初始行,但 Tie::File 会对您隐藏详细信息。)
一个好的 Perl 习惯用法是读写标准输入和输出。您可以根据需要进行管道传输和重定向。通过运算符 <>(readline 的换行),Perl 将打开您在命令行上作为参数传递的文件。
为了回答你的问题,几行代码(尽可能干净):
#!/usr/bin/env perl
use strict; use warnings;
while (<>) {
if ($. == 2) {
print "new data", "\n";
next;
}
if ($. == 3) {
print "very new data", "\n";
next;
}
print;
}
print "more data", "\n";
然后这样称呼它:perl yourscript.pl 输入文件>输出文件
如果您想自己打开文件(这里我们只是跳过不需要的行):
my open $in_fh, '<', $inputfile
or die "Can't open file $inputfile: $!";
my open $out_fh, '>', $outputfile
or die "Can't open file $output: $!";
while (my $line = <$in_fh>) {
next if ( $. == 2 or $. == 3 or $. == 4 );
print $out_fh $line;
}
print $out_fh "...whatever\n";
如果您以“追加模式”打开文件,则无法“替换”打开文件时已存在于文件中的行。追加文件意味着您的程序只能读取文件并添加到文件末尾。 您可以创建一个新文件,向其中添加内容(可能基于不同文件中的内容),然后将新文件复制到另一个文件上。 我想我不太明白这个作业。