[BNE-PM] The Perl one-liner
Derek Thomson
derek at wedgetail.com
Wed Sep 18 20:14:41 CDT 2002
[I'm posting my reply to the list, as the answer may be generally
helpful, and I'm pretty sure you meant the original to go to the list!]
Mike Bissett wrote:
>
>
>>
>>$ perl -pe 's/Foo/Bar/g'
>
>
> I always wondered what those lfags did :) now i know.
>
Yes, they're great, aren't they? For more deviousness, check out the
perlrun manpage for the "-a" flag. If no one uses it in a response, I'll
give a brief run-down of its wonderousness in combination with "-p",
"-n", and "-e".
>
> I tried Something like
>
> perl -ne 'print if /$_/'
>
> but i couldnt work out how to pass my search string as an
> arg to perl (it assumes im calling a script) any ideas ?
Close.
But this is matching the line read against *itself*. I'll expand this a
little to make this clear. What this means is:
$ perl -ne 'print if $_ =~ /$_/'
See? You really want to match the line against the pattern, like this:
$ perl -ne 'print if $_ =~ /Foo/'
... but because the match "//" operator works on the "$_" variable by
default, you can reduce this to:
$ perl -ne 'print if /Foo/'
Now, if you're using this on the command line, there's no need to pass
an arg to Perl, you just put the pattern right into the code:
$ ls | perl -ne 'print if /(Foo).*\1/'
... selects all those files with two "Foo"s in the name.
If you do want to pass command line arguments to Perl (say if you were
writing 'pgrep', a Perl alternative to 'grep') you'd use the @ARGV
array, which contains all the arguments given to the program.
So, a first stab at pgrep might be:
#!/usr/bin/perl -w
use strict;
sub show_usage();
#
# Grab the first command line argument off the array, it is the regex
# pattern to match against.
#
show_usage and exit 1 if @ARGV < 1;
my $pattern = shift @ARGV;
#
# Read each line from the remaining arguments (files) on the command
# line and then from stdin.
#
while (<>) {
# Print the line if it matches the pattern.
print if /$pattern/;
}
#
# Print out the program usage information.
#
sub show_usage()
{
print << 'END_USAGE';
Usage:
pgrep pattern [file] ...
END_USAGE
}
Now you can say:
$ ls | pgrep '(Foo).*\1'
... to do the same thing. Because of the magic way the '<>' operator
works, you can also match against any number of files:
$ pgrep '(Foo).*\1' file1 file2 file3
>
> P.S. for those interested my brother has finally gotten
> round to putting his pictures of the last meeting online
> at
> http://www.tekuiti.co.uk/photos/index.cgi?mode=album&album=./Holiday%203
Beaut!
--
D.
More information about the Brisbane-pm
mailing list