Re: upto match please, my one-lina!!
by davidrw (Prior) on Jun 09, 2006 at 00:26 UTC
|
the obivous solution first :)
egrep -B4 /foo/ file
for perl, maybe like (not sure you want to slurp .. this just keeps an array of the last N lines):
# put the line into the cache/queue; shorten the array if it's more t
+han we want; print the array if current line mataches.
perl -ne 'push @lines, $_; shift @lines if scalar(@lines)>4; print jo
+in "", @lines if /foo/' file
# if you don't want the current line printed as one of the 4, just rea
+rrange a little:
perl -ne 'print join "", @lines if /foo/; push @lines, $_; shift @lin
+es if scalar(@lines)>4' file
or, using Tie::File:
use Tie::File;
use Fcntl 'O_RDONLY';
my @array;
tie @array, 'Tie::File', $ARGV[0], mode => O_RDONLY or die;
foreach my $i ( 0 .. $#array ){
# no, doesn't handle index edge case of $i < 4
print join "", @array[$i-4,$i-1] if $array[$i] =~ /foo/;
}
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: upto match please, my one-lina!!
by roboticus (Chancellor) on Jun 09, 2006 at 00:24 UTC
|
perl -ne 'print @t if /foo/; push @t,$_; shift @t if $#t>5' file
You can even slice @t in the print if you want to have a larger gap between the last printed item and the regular expression...
UPDATE: I golfed it down a little:
perl -ne 'print @t if /foo/; @t=(@t[1..4],$_)' file
--roboticus | [reply] [Watch: Dir/Any] [d/l] [select] |
|
That doesn't print the "---\n" string or the correct lines. You want something like:
perl -ne'@t=(@t[1..4],$_);/regex/&&die@t,"---\n"' file
| [reply] [Watch: Dir/Any] [d/l] |
|
perl -ne '@t=(@t[1..4],$_,"---\n");die@t if/foo/' file
--roboticus
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
Re: upto match please, my one-lina!!
by jmcnamara (Monsignor) on Jun 09, 2006 at 00:35 UTC
|
Here is a one-liner that emulates grep -B (although not as elegantly for adjacent matches):
perl -ne '$a[$i=$.%4]=$_; print @a[$i+1..$#a,0..$i], "--\n" if /re
+gex/' file
--
John.
| [reply] [Watch: Dir/Any] [d/l] |
|
Thanks guys .. looks like it's a ubiquitous solution although approached via TMTOWTDI. Sure beats my long ineffeciency. :)
| [reply] [Watch: Dir/Any] |
Re: upto match please, my one-lina!!
by NetWallah (Canon) on Jun 09, 2006 at 00:55 UTC
|
I'm adding my $0.02, in case the OP wants (as indicated by the OP's code) to print only the first occurrance of the match.
perl -ne "push @a,$_;m/foo/ and exit 1;shift @a if $#a>3;END{$?==1 and
+ print @a }" myfile.txt
Update: as japhy points out below, this is Win32 syntax. Use single-quotes for *nix.
"For every complex problem, there is a simple answer ... and it is wrong." --H.L. Mencken
| [reply] [Watch: Dir/Any] [d/l] |
|
$ which perl
/usr/bin/perl
$ perl -ne "push @a,$_; /foo/ and exit 1; shift @a if $#a>3; END{$?==1
+ and print @a }" file
Bareword found where operator expected at -e line 1, near "0a"
(Missing operator before a?)
syntax error at -e line 1, near "0a"
Execution of -e aborted due to compilation errors.
That sure is unexplained .. 0a??? where'd that come from.
Seems the double quotes are playing a part in inducing this behaviour. Under singles it works fine.
| [reply] [Watch: Dir/Any] [d/l] |
|
NetWallah is probably on Win32, where the double-quotes are necessity. Your unixy shell is interpolating $# and replacing it with '0' in your code; thus: shift @a if 0a>3;
| [reply] [Watch: Dir/Any] [d/l] |
Re: upto match please, my one-lina!!
by ioannis (Abbot) on Jun 09, 2006 at 03:32 UTC
|
So it can run also under use strict:
perl -Mstrict \
-ne'/regex(?{print @@; exit})/;' \
-e'shift(@@) if push(@@,$_)>5' file
| [reply] [Watch: Dir/Any] [d/l] |
|
Loved the clever use of the return value from push, ioannis (++). The 'experimental' regex feature, however, got me thinking if it could be done with regular features only, so - here is the slightly ugly, but short:
perl -ne "m/foo/ and die @@ ; shift(@@) if push(@@,$_)>5" myfile.txt
I used "die" because (without eval), the "print @@, exit" combo printed nothing in my code (but it works as advertised in ioannis' code). Perhaps a more enlightened monk could explain why.
Update: This works too:
perl -Mstrict -ne "m/addr/ and eval {print @@; exit}; shift(@@) if pus
+h(@@,$_)>5" myfile.txt
This code works on Win32. Use single-quotes for *nix.
"For every complex problem, there is a simple answer ... and it is wrong." --H.L. Mencken
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: upto match please, my one-lina!!
by japhy (Canon) on Jun 09, 2006 at 01:33 UTC
|
perl -ne 'BEGIN { $pat = qr/.../; $size = (N-1) } @_ = ($_, @_[0 .. ($
+#_ > $size ? $size : $#_)]); print reverse @_ if /$pat/'
| [reply] [Watch: Dir/Any] [d/l] |
|
Jeff,
Thanks for pointing $# out .. didnt realize that one.
Errm, i dont see the point to the code ..
seems like a long way around
perl -ne 'print if /(?-xism:.{3})/'
| [reply] [Watch: Dir/Any] [d/l] |
|
Huh? I presented code that prints N lines before a matching line.
| [reply] [Watch: Dir/Any] |