[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