开发者

How can I read all of the lines between two lines in a file, using Perl?

I have one file where t开发者_Go百科he contents looks like:

pch
rch
channel
cap
nch
kappa
.
.
.
kary
ban
....

Now I want to read my file from nch to kary and copying those lines only in some other file. How can I do this in Perl?


If I understand your question correctly, this is pretty simple.

    #!perl -w
    use strict;
    use autodie;

    open my $in,'<',"File1.txt";
    open my $out,'>',"File2.txt";

    while(<$in>){
    print $out $_ if /^nch/ .. /^kary/;
    }


From perlfaq6's answer to How can I pull out lines between two patterns that are themselves on different lines?


You can use Perl's somewhat exotic .. operator (documented in perlop):

perl -ne 'print if /START/ .. /END/' file1 file2 ...

If you wanted text and not lines, you would use

perl -0777 -ne 'print "$1\n" while /START(.*?)END/gs' file1 file2 ...

But if you want nested occurrences of START through END, you'll run up against the problem described in the question in this section on matching balanced text.

Here's another example of using ..:

while (<>) {
    $in_header =   1  .. /^$/;
    $in_body   = /^$/ .. eof;
# now choose between them
} continue {
    $. = 0 if eof;  # fix $.
}


You could use this in 'sed':

sed -n /nch/,/kary/p $file

You could use 's2p' to convert this to Perl.

You could also write pure Perl:

while (<>)
{
    next unless /nch/;
    print;
    while (<>)
    {
        print;
        last if /kary/;
    }
}

Strictly, both these solutions will print each set of lines from 'nch' to 'kary'; if 'nch' appears more than once, it will print more than one chunk of code. It is easy to fix that, especially in the pure Perl ('sed' solution left as an exercise for the reader).

OUTER:
while (<>)
{
    next unless /nch/;
    print;
    while (<>)
    {
        print;
        last OUTER if /kary/;
    }
}

Also, the solutions look for 'nch' and 'kary' as part of the line - not for the whole line. If you need them to match the whole line, use '/^nch$/' etc as the regex.


Something like:

$filter = 0;
while (<>) {
  chomp;
  $filter = 1 if (! $filter && /^nch$/);
  $filter = 0 if ($filter && /^ban$/);
  print($_, "\n") if ($filter);
}

should work.


if you only want to read one block, in gawk

gawk '/kary/&&f{print;exit}/nch/{f=1}f' file

in Perl

perl -lne '$f && /kary/ && print && exit;$f=1 if/nch/; $f && print' file

or

while (<>) {
    chomp;
    if ($f && /kary/) {
        print $_."\n";
        last;
    }
    if (/nch/) { $f = 1; }
    print $_ ."\n" if $f;
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜