Это не специальный оператор, это два стандартных оператора один за другим:
--
) !
) Это приводит к тому, что значение pending
уменьшается, а затем проверяется на нулевое значение.
Вы хотите что-то вроде этого:
my @grabbed;
while (<FILE>) {
if (/TARGET/) {
push @grabbed, $_;
while (<FILE>) {
last if /^$/;
push @grabbed, $_;
}
}
}
Оператор диапазона идеально подходит для такого рода задач:
$ cat try
#! /usr/bin/perl
while (<DATA>) {
print if /\btarget\b/i .. /^\s*$/
}
__DATA__
Line 1
Line 2
Line 3
Line 4 Target
Line 5 Grab this line
Line 6 Grab this line
Nope
Line 7 Target
Linu 8 Yep
Nope again
$ ./try
Line 4 Target
Line 5 Grab this line
Line 6 Grab this line
Line 7 Target
Linu 8 Yep
Короткий ответ: разделитель строк в Perl - $ /
, поэтому, нажав TARGET, вы можете установить $ /
на » \ n \ n "
, прочтите следующую" строку ", затем установите ее обратно на" \ n "... et voilà!
Теперь о более длинном: если вы используете английский
] (который дает разумные имена всем магическим переменным Perl, тогда $ /
называется $ RS
или $ INPUT_RECORD_SEPARATOR
. Если вы используете IO :: Handle
, тогда IO :: Handle-> input_record_separator ("\ n \ n")
будет работать.
И если вы делаете это как часть большего фрагмента кода , не забудьте либо локализовать (используя local $ /;
в соответствующей области) или вернуть $ /
к исходному значению "\ n"
.
use strict;
use warnings;
my $inside = 0;
my $data = '';
while (<DATA>) {
$inside = 1 if /Target/;
last if /^$/ and $inside;
$data .= $_ if $inside;
}
print '[' . $data . ']';
__DATA__
Line 1
Line 2
Line 3
Line 4 Target
Line 5 Grab this line
Line 6 Grab this line
Next Line
Отредактируйте, чтобы исправить условие выхода в соответствии с примечанием ниже.
while(<FILE>)
{
if (/target/i)
{
$buffer .= $_;
while(<FILE>)
{
$buffer .= $_;
last if /^\n$/;
}
}
}
Если вы не возражаете против уродливого автоматически сгенерированного кода и предполагаете, что вам нужны только строки между TARGET
и следующей пустой строкой, а все остальные строки должны быть упал, вы можете использовать вывод этой команды:
s2p -ne '/TARGET/,/^$/p'
(Да, это намек на то, что эту проблему обычно гораздо легче решить в sed
. :-P)
Если вам нужен только один цикл (модификация кода Дэйва Хинтона):
my @grabbed;
my $grabbing = 0;
while (<FILE>) {
if (/TARGET/ ) {
$grabbing = 1;
} elsif( /^$/ ) {
$grabbing = 0;
}
if ($grabbing) {
push @grabbed, @_;
}
}
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 $.
}