Как заменить строки в середине файла на Perl? - PullRequest
20 голосов
/ 17 февраля 2010

Я открываю файл в режиме добавления. Мне нужно заменить строки 2,3 и 4 в файле, а позже мне нужно добавить новые данные в конец файла.

Ответы [ 5 ]

41 голосов
/ 22 февраля 2010

Я думаю, что это ответ на часто задаваемые вопросы, который я разместил в Stackoverflow больше всего. 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 для изменения файла на месте. Следующее изменяет все 'Fred' на 'Barney' в inFile.txt , перезаписывая файл новым содержимым. С переключателем -p Perl оборачивает цикл while вокруг кода, который вы указали с помощью -e, а -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
4 голосов
/ 17 февраля 2010

Вы можете сделать это с помощью Tie :: File . (Имейте в виду, что для замены начальных строк придется переписать весь файл, но Tie :: File скроет от вас детали.)

3 голосов
/ 17 февраля 2010

Хорошая идиома 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 inputfile> outputfile

Если вы хотите открыть файлы самостоятельно (здесь мы просто пропускаем ненужные строки):

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";
0 голосов
/ 17 февраля 2010
use File::Copy;

        copy("/file1.txt","/file1_old.txt");
        open(FILEHANDLE,">file1.txt");
        open(FILEHANDLE1,"<file1_old.txt");

        my $linecount=1;
        while(<FILEHANDLE1>)
        {
            print $_."\n";

            if($linecount>4)
            {
                print FILEHANDLE "$_";
            }
            $linecount++;
        }

        {
                ## new data will be placed
        }
        #####close the file handle
         close(FILEHANDLE1);
         close(FILEHANDLE);
0 голосов
/ 17 февраля 2010

Если вы откроете файл в режиме добавления , вы не сможете заменить строку, которая уже была в файле при его открытии. Добавить файл означает, что ваша программа имеет возможность только прочитать файл и добавить его в конец.

Вы можете создать новый файл, добавить к нему содержимое (возможно, на основе содержимого из другого файла), а затем скопировать новый файл поверх другого файла.

Полагаю, я не совсем понимаю назначение.

...