我想在文件的顶部和底部添加一行。我可以按照以下方式做到。
open (DATA, "</usr/old") || die "cant open old\n"; #file to which line has to be added
my @body=<DATA>;
close(DATA);
open (FILE, ">/usr/new") || die "cant open new\n"; #file after stuff has been added
print FILE "9 431";
print FILE "\n";
my $body=@body;
for (my $i=0; $i<$body;$i++){
print FILE "$body[$i]";#not using for loop leads to addition of spaces in new file
}
print FILE "(3,((((1,4),(7,6)),(2,8)),5),9)";
由于我运行大量文件,因此这个过程非常耗时。 Perl是否具有用于在文件顶部和底部添加行的任何特定功能?
答案 0 :(得分:10)
从perlfaq5回答How do I change, delete, or insert a line in a file, or append to the beginning of a file?
如何更改,删除或插入文件中的行,或附加到文件的开头?
(由brian d foy提供)
从文本文件中插入,更改或删除行的基本思想包括读取和打印文件到要进行更改的位置,进行更改,然后读取和打印文件的其余部分。 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
答案 1 :(得分:2)
Perl无法在文件开头插入,因为很少有操作系统允许这样做。您需要重写此类型的重写操作。
该代码可能遇到的一个问题是您的地址空间无法容纳的真正大文件。
通过读取整个文件然后将其写出来,可能会遇到内存问题。我本来会做的是:
这将是快速且节省内存的。
当然,如果您的文件足够小以适应内存,请坚持使用您拥有的文件。这很好。
更新
足够的人似乎在误解我正在倡导一个我认为我会直接设置的shell脚本。您可以在本机Perl中执行上述所有操作。
但您可能想要考虑是否有必要使用Perl。 shell命令如:
( echo '9 431';cat /usr/old;echo '(3,((((1,4),(7,6)),(2,8)),5),9)' ) >/usr/new
也可以做到这一点(也可能同样快)。
当然,如果你需要 Perl,那么就把这个更新当作一个老人的乱骂: - )
答案 2 :(得分:2)
使用Tie::File,可以通过Perl数组访问磁盘文件的行。它带有标准发行版。
文档示例:
use Tie::File;
tie @array, 'Tie::File', filename or die ...;
$array[13] = 'blah'; # line 13 of the file is now 'blah'
print $array[42]; # display line 42 of the file
$n_recs = @array; # how many records are in the file?
$#array -= 2; # chop two records off the end
for (@array) {
s/PERL/Perl/g; # Replace PERL with Perl everywhere in the file
}
# These are just like regular push, pop, unshift, shift, and splice
# Except that they modify the file in the way you would expect
push @array, new recs...;
my $r1 = pop @array;
unshift @array, new recs...;
my $r2 = shift @array;
@old_recs = splice @array, 3, 7, new recs...;
untie @array; # all finished
答案 3 :(得分:1)
已经给出了三个答案,这些答案延续了非常糟糕的做法:
open(FILE,"<file") or die "cannot open";
不仅如此,代码被破坏了,因为你没有打开文件进行写作而是阅读。
当打开失败时,您可以告诉用户为什么失败。请养成包含$的习惯!在错误消息中。另外,使用open
的三个参数形式将模式与名称分开:
my $path="file";
open my($fh), '>', $path or die "$path: $!";
(这不能回答你的问题,但是我把它作为一个答案,而不是一个评论,以增加重点,以便我可以审查它,因为它是一个相当漫长的喷出。)
答案 4 :(得分:0)
你可以这样做
open(FILE,">", $file) or die "cannot open $file: $!";
print FILE "add line to top\n";
while (<FILE>) { print $_ ."\n";}
close(FILE);
print FILE "add line to bottom\n";
在命令行上
perl myscript.pl > newfile
答案 5 :(得分:0)
有许多方法可以做到这一点,例如使用简单的shell脚本,就像@Pax提到的那样。您还可以使用join()替换数组和循环:
open(DATA, "</usr/old") || die "cant open old\n"; #file to which line has to be added
my $body=join("", <DATA>);
open (FILE, ">/usr/new") || die "cant open new\n"; #file after stuff has been added
print FILE "9 431\n";
print(FILE $body);
print FILE "(3,((((1,4),(7,6)),(2,8)),5),9)";
close(FILE);
答案 6 :(得分:0)
我对ghostdog74的修改是文件句柄应该在print语句中,文件应该在第二个print语句后关闭。
open(FILE, ">", "file") or die "cannot open $file: $!";
print FILE "add line to top";
while (<FILE>) { print $_;}
print FILE "add line to bottom";
close(FILE);
答案 7 :(得分:-1)
正如Pax所说,没有内置的方法可以做到这一点。但是如果你想用shell中的单行perl命令来实现它,你可以使用:
perl -ple 'print "Top line" if $. == 1; if (eof) { print "$_\nBottom line"; exit; }' yourfile.txt > newfile.txt