使用perl更改textfile中的行

时间:2015-10-25 07:33:20

标签: perl

我在其他地方读到了如何做到这一点,但他们让我感到困惑。

我想从文本文件中读取行,当我遇到某一行时,我想向其添加内容。

我的代码是:

 open my $p, "$username_filename" or die "can not open $username_filename: $!";

 foreach $line (<$p>){
     if ($line =~ /^listen/){
         `echo "whatever" >> $username_file`;
     }
 }

然而,当我运行此操作时,我收到此错误

sh: -c: line 0: syntax error near unexpected token `newline' sh: -c: line 0: `echo "current_user" >> '

编辑文件是否正确?为什么我会收到此错误?

2 个答案:

答案 0 :(得分:6)

使用文件与在文字处理器中编辑不同。线条是幻觉,文件只是一大串字符。您无法更改文件中间的行,原因与您无法更改书中间的行相同,无法移动单词以腾出空间。

相反,就像一本书一样,如果你想改变一些东西,你需要改写整个事物。

基本算法是......

  1. 打开文件进行阅读。
  2. 打开一个临时文件进行写作。
  3. 读一行,改变行,写行。
  4. 重复3直到完成阅读。
  5. 使用临时文件覆盖文件。
  6. 其他一些说明......

    print默认写入STDOUT,但你可以给它一个文件句柄来代替。

    遗憾的是,

    foreach my $line (<$fh>)未针对文件进行优化。它会将可能很大的文件读入内存。 while(my $line = <$fh>)一次读取一行。

    我已打开strict。这会强制您声明变量。它可以保护您免受类似于$username_file vs $username_filename

    的拼写错误

    您可以使用"$filename.tmp"之类的内容,但File::Temp提供的临时文件可以保证是临时的,唯一的,并在程序退出时进行清理。

    use strict;
    use warnings;
    use autodie;     # because writing 'or die' gets old fast
    use File::Temp;  # provides safe temp files    
    
    my $filename = ...; # set it somehow
    
    open my $read, "<", $filename;
    my $temp = File::Temp->new;
    
    while(my $line = <$read>) {
        if( $line =~ /^listen/ ) {
            chomp $line;             # remove the newline
            $line .= " whatever\n";  # add our content and put a newline back
        }
    
        # Write the line to the temp file
        print $temp $line;
    }
    
    # Overwrite our file with the rewritten temp file
    rename $temp->filename, $filename;
    

    这是一个程序。如果您只想快速完成,可以使用-i-p在命令行上执行此操作。

    perl -i.bak -pe 'if( /^listen/ ) { chomp; $_ .= "whatever" }' filename
    

    -p表示要在文件的每一行上运行代码。该行将被放入$_,并且将打印$_中的任何内容。 -i表示要编辑文件。 -i.bak会对原始文​​件进行备份,以防您出错。

答案 1 :(得分:2)

您的尝试存在一些问题。最重要的是使用echo >> file将附加到文件,而不是插入文件中的任意位置。

另一个问题是,您尝试附加到名为$username_file的文件,并且您尚未声明或定义该变量。

我不认为perl允许您插入文件的中间。我认为你最好的选择是一次读取一行文件,并在正确的行上添加你想要的文本。将每一行写入一个新文件,然后在最后交换文件。

例如:

#!/usr/bin/perl
my $in_filename = "in.txt";
my $out_filename = "out.txt";

open (my $in, "<", $in_filename) or die;
open (my $out, ">", $out_filename) or die;

while (my $lline = <$in>)
{
    chomp $lline;
    if ( $lline =~ /listen/ )
    {
        print "$lline whatever\n";
    }
    else
    {
       print "$lline\n";
    }
 } 

close $in;
close $out;

rename $in_filename, "$in_filename.original";
rename $out_filename, $in_filename;

我使用chomp删除行结尾,因为<$in>为我们提供了一行,包括行结尾,否则会混淆附加内容。

一如往常,有很多方法可以实现这一目标。我认为使用sed可能是一个更好的选择,但你明确地问过如何在perl中这样做,所以Perl就是。