简体   繁体   English

使用Perl更改文本文件中的行

[英]Change line in textfile using perl

I read other places on how to do this but they were confusing for me. 我在其他地方阅读了有关如何执行此操作的信息,但它们让我感到困惑。

I want to read lines from a text file and when I come across a certain line I want to append something to it. 我想从文本文件中读取行,当遇到某行时,我想向其添加一些内容。

My code is: 我的代码是:

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

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

However when I run this I get this error 但是,当我运行这个我得到这个错误

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

Is this way correct to edit the file and why am I getting this error? 这样编辑文件的方法正确吗,为什么会出现此错误?

Working with files is not like editing in a word processor. 处理文件不像在文字处理器中进行编辑。 Lines are an illusion, a file is just a big string of characters. 行是一种错觉,文件只是一大串字符。 You can't change a line in the middle of a file for the same reason you can't change a line in the middle of a book, the words can't be moved around to make room. 出于相同的原因,您不能在文件的中间更改行,而在书的中间也不能更改行,单词也不能四处移动以腾出空间。

Instead, like a book, if you want to change something you need to rewrite the whole thing. 相反,就像一本书一样,如果您想更改某些内容,则需要重写整个内容。

The basic algorithm is to... 基本算法是...

  1. Open the file for reading. 打开文件进行读取。
  2. Open a temporary file for writing. 打开一个临时文件进行写入。
  3. Read a line, alter the line, write the line. 读一行,更改行,写一行。
  4. Repeat 3 until done reading. 重复3直到完成阅读。
  5. Overwrite the file with the temp file. 用临时文件覆盖文件。

Some other notes... 其他注意事项...

print writes to STDOUT by default, but you can give it a filehandle to write to instead. 默认情况下, print写入STDOUT,但是您可以给它一个文件句柄来写入。

foreach my $line (<$fh>) is unfortunately not optimized to read files. 不幸的是, foreach my $line (<$fh>)并未针对读取文件进行优化。 It will read the possibly enormous file into memory. 它将可能巨大的文件读入内存。 while(my $line = <$fh>) reads one line at a time. while(my $line = <$fh>)读取一行。

I've turned on strict . 我已启用strict This forces you to declare your variables. 这迫使您声明变量。 It protects you from typos like the one you made of $username_file vs $username_filename . 它可以保护您免受$username_file$username_filename造成的错字。

You could use something like "$filename.tmp" but File::Temp provides temp files that are guaranteed to be temporary, unique and cleaned up when the program exits. 您可以使用"$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;

That's inside a program. 在程序内部。 If you just want to do it quickly, you can do it on the command line with -i and -p . 如果只想快速执行此操作,则可以在命令行上使用-i-p

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

-p says to run the code on each line of the file. -p表示在文件的每一行上运行代码。 The line will be put into $_ and whatever is in $_ will be printed. 该行将放入$_并且将打印$_任何内容。 -i says to edit the file in place. -i说要在适当位置编辑文件。 -i.bak makes a backup of the original file just in case you make a mistake. -i.bak会备份原始文件,以防万一您出错。

There are a few problems with your attempt. 您的尝试有一些问题。 The big one is that using echo >> file will append to the file, not insert at some arbitrary place inside the file. 最大的问题是使用echo >> file将追加到文件中,而不是插入文件中的任意位置。

Another problem is that you're trying to append to a file called $username_file , and you haven't declared or defined that variable. 另一个问题是,您试图追加到名为$username_file的文件中,但尚未声明或定义该变量。

I don't think perl lets you insert into the middle of a file. 我认为perl不能让您插入文件的中间。 I think your best bet would be to read the file a line at a time, and on the correct line(s), append the text you want. 我认为最好的选择是一次一行地读取文件,并在正确的行上附加所需的文本。 Write each line to a new file, then swap the files around at the end. 将每一行写入一个新文件,然后最后交换文件。

For example: 例如:

#!/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;

I use chomp to remove line endings, because <$in> gives us a line including its line endings, wish otherwise messes up the append. 我使用chomp删除行尾,因为<$in>给我们一行包括其行尾的内容,否则希望弄乱附加内容。

As always there are many ways to achieve this. 与往常一样,有很多方法可以实现这一目标。 I think using sed is probably a better option for this, but you specifically asked how to do it in perl, so perl it is. 我认为使用sed可能是一个更好的选择,但是您特别询问了如何在perl中进行操作,因此是perl。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM