【问题标题】:Copy selected lines from one file and insert those lines in another file after selected line从一个文件中复制选定的行并将这些行插入到另一个文件中的选定行之后
【发布时间】:2015-01-09 14:08:13
【问题描述】:

这是我的问题,假设我有一个文件 file1.txt 内容:

abc.. 
def.. 
ghi.. 
def..

第二个文件file2.txt 的内容:

xxx..
yyy..
zzz..

现在我想将file1.txt中以“def”开头的所有行复制到file2.txt,并在file2.txt中的“yyy...”行之后追加

预期输出:

xxx...
yyy...
def...
def...
zzz...

我对 perl 很陌生,我尝试为此编写简单的代码,但最终输出只附加在文件末尾

#!/usr/local/bin/perl -w 
use strict; 
use warnings;
use vars qw($filecontent $total);
my $file1 = "file1.txt";
open(FILE1, $file1) || die "couldn't open the file!";
open(FILE2, '>>file2.txt') || die "couldn't open the file!";
  while($filecontent = <FILE1>){
    if ( $filecontent =~ /def/ ) {
      chomp($filecontent);
       print FILE2 $filecontent ."\n";
      #print FILE2 $filecontent ."\n" if $filecontent =~/yyy/;
    }  
  } 
 close (FILE1); 
 close (FILE2);

perl 程序的输出是

xxx...
yyy...
zzz...
def...
def...

【问题讨论】:

  • 您正在使用&gt;&gt; 打开file2。因此,您会将输出附加到file2末尾。因此,一种方法是:打开file3。复制从file2yyy... 的所有内容。然后使用您的while 语句,然后将file2 的其余部分复制到file3
  • 不鼓励使用use vars。您应该使用my 在此处声明变量,而不是使用全局变量,而是在尽可能小的范围内声明变量,最好是在使用它们的位置。例如。 while (my $filecontent = &lt;FILE1&gt;).
  • 你的文件有多大?

标签: perl


【解决方案1】:

我会使用临时文件。

  1. 从 FILE2 读取并打印所有行(到 temp),直到您点击“yyy”
  2. 从 FILE1 读取并打印所有“def”行(到 temp)
  3. 读取并打印(临时)FILE2 的其余部分
  4. 将临时文件重命名为 FILE2
use strict; 
use warnings;

my $file1 = "file1.txt";
my $file2 = "file2.txt";
my $file3 = "file3.txt";

open(FILE1, '<', $file1) or die "couldn't open the file!";
open(FILE2, '<', $file2) or die "couldn't open the file!";
open(FILE3, '>', $file3) or die "couldn't open temp file";

while (<FILE2>) {
  print FILE3;
  if (/^yyy/) {
    last;
  }
}

while (<FILE1>) {
  if (/^def/) {
    print FILE3;
  }
}

while (<FILE2>) {
  print FILE3;
}

close (FILE1); 
close (FILE2);
close (FILE3);

rename($file3, $file2) or die "unable to rename temp file";

【讨论】:

  • 简单而强大的+1。您可能希望在 die 消息中包含文件名和错误,例如die "couldn't open $file1: $!"。还建议使用词法文件句柄,例如my $file1 而不是 FILE1。此外,File::Copy::move() 有时比内置的 rename 更受欢迎。
  • 所有优点 - 只是不想偏离原始代码比必要的更远,以使 OP 消化的更改更少。虽然File::Copy::move() 更灵活,但在这个简单的例子中,我们完全需要rename() 所做的一件事,不需要额外的包导入。
  • 我认为使用正确的代码是必不可少的,因为这是一个学习环境。以身作则,等等。
  • @TLP 在死亡消息期间很好地捕捉到了 $file1,当我尝试 File::Copy::move() 时,导致在..perl-5.8.3/lib/5.8 中使用了未初始化的值。 3/File/Copy.pm 第 184 行。已移至更简单的方法。
  • @vjemmaN 您删除了错误消息的关键部分。 File/Copy.pm 中的第 184 行是 close($to_h) || goto fail_open2 if $closeto;,唯一可以得到未初始化警告的是 close,而且不太可能是这样。
【解决方案2】:

最简单的方法是使用Tie::File 模块,它允许您以简单的字符串数组的形式访问文件。

我还使用List::MoreUtils 中的first_index 来查找插入记录的位置。

use strict;
use warnings;

use Tie::File;
use List::MoreUtils qw/ first_index /;

tie my @file1, 'Tie::File', 'file1.txt' or die $!;
tie my @file2, 'Tie::File', 'file2.txt' or die $!;

my $insert = first_index { /^yyy/ } @file2;

for (@file1) {
  if ( /^def/ ) {
    splice @file2, ++$insert, 0, $_;
  }
}

输出 (file2.txt)

xxx..
yyy..
def.. 
def..
zzz..

您的测试数据没有覆盖它,但是来自file1.txt 的记录会按照它们出现的顺序插入到file2.txt

【讨论】:

    【解决方案3】:

    您可能想尝试IO::All 模块:

    use IO::All;
    my ($f1, $f2, $i) = (io('file1.txt'), io('file2.txt'), 1);
    for (@$f2) {
        splice(@$f2, $i, 0, grep /^def/, @$f1), last
            if /^yyy/;
        $i++;
    }
    

    【讨论】:

      猜你喜欢
      • 2014-01-26
      • 1970-01-01
      • 2018-04-21
      • 1970-01-01
      • 1970-01-01
      • 2016-06-06
      • 1970-01-01
      • 2018-03-10
      • 1970-01-01
      相关资源
      最近更新 更多