My own handy Pocket Reference notes

D

David Filmer

In a previous thread
(http://groups.google.com/groups?hl=...16dd.0408111652.3099c07c%40posting.google.com)
I posted a transcription of little hints/shortcuts that I have written
inside the covers of my Perl Pocket Reference over the years. A number
of helpful people have kindly provided corrections/comments (thanks!).
Although nobody suggested any brand-new items, some comments led me to
include alternate approaches for some items and some additional
content not previously covered.

I have made some effort to group similar items (some could fall into
multiple categories). As before, the notes are 70-col wide (displays
nice Google Groups, which is the only usenet access for many people
behind corp. firewalls). If printed in 6pt Courier it's 9cm wide -
fits nicely inside the cover of a Pocket Reference.

These are mainly syntax HINTS. In some cases the examples are so
trivial that other methods would be preferred. And, of course, there
are often many ways to
do things. This is not a HOWTO.

So here are my corrected/modified notes, provided here in the hope
that someone else might find them useful:

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
============================================= VARIABLE MANIPUTATION ==
Instead of: $a = $b; $a = s/foo/bar/; ($a as a modified version of $b)
($a = $b) =~ s/foo/bar/;
======================================================================
Instead of: $a =~ /foo(.*)/; $b = $1; ($a as a substring of $b)
($b) = ($a =~ /foo(.*)/);
======================================================================
To strip leading or trailing spaces:
$foo =~ s/^\s+//; $foo =~ s/\s+$//;
OR s/^\s+//, s/\s+$// for $foo; # To do both sides at once
======================================================================
To set a variable but ONLY if it is currently undefined/zero/null:
$foo ||= 'bar';
======================================================================
To set a variable to the greater (larger) of two choices:
$var = ($a > $b) ? $a : $b;
Similarly, to (for example) print if a number is even or odd:
print "The number is ", ($num % 2) ? "odd" : "even"; # % is modulo
======================================================================
To round off a number to "n" decimal places (or use Number::Format)
sprintf ("%.nf", $foo); #replace "n" with a variable or constant
======================================================================
To strip the path from a filename (such as $0) w/o File::Basename:
print $0 =~ m{([^/]*)$}; #or $0 =~ (/^.*\/(.*)/)[0]
======================================================================
To embed a variable in a variable name (causes the earth to explode):
$foo = "foo"; print ${"${foo}bar"}; #same as ${'foobar'} or $foobar
#symbolic reference-bad idea. Try to use real ref or hash data struct
======================================================================
To generate a random integer between 0 and 10 (inclusive):
$foo = int rand(11); #or int rand(10)+1 between 1 and 10 inclusive
======================================================================
To replace $foo with $bar across an array
@list2 = map s/$foo/$bar/, @list; #or map {s/$foo/$bar/} @list;
print s/$foo/$bar/ for @list #ie, void context
map {$_ =~ s/$foo/$bar/g} @LIST #changes @LIST
======================================================================
To sort an array numerically (instead of Perl default alpha sort):
@sorted = sort { $a <=> $b } @unsorted; #Perl Cookbook 1ed p115

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
======================================================= SUBROUTINE ==
To pass a filehandle (FH) the proper way, (for example with CGI.pm):
$foo = new CGI (\*FH);
======================================================================
To pass a only single hash to a subroutine (without using references):
&MySubroutine(%foo); #call the sub and pass it a hash directly
sub MySubroutine { my %bar = @_; ...etc... }
======================================================================
To pass a hash from a subroutine:
%foo = my_sub();
sub my_sub {$bar{'candy'}='chocolate'; return %bar; }

OR %foo = %{&MySubroutine()};
sub MySubroutine { my $bar{'candy'}='chocolate'; return \%bar; }
======================================================================
Subroutine Prototypes. SYNTAX: if_defined_this_way #call_this_way
sub foo($) #foo $bar1 | sub foo(\@) #foo @bar
sub foo($$) #foo $bar1 $bar2 | sub foo(\%) #foo %{$hashref}
sub foo($$;$) #foo $b1, $b2, $opt | sub foo(*) #foo *bar
sub foo(@) #foo $b1,$b2,$b3 | sub () #foo
======================================================================
To pass by reference to/from subroutine:
@a = (1..3); @b = (4..6);
($s_ref, $p_ref) = do_math (\@a, \@b); #sum/multply mbrs of @a & @b
print "Sum: @{[join ',',@{$s_ref}]} Prod: @{[join ',',@$p_ref]}\n";

sub do_math { #add and multiply values of two lists (no err chk!)
while(@{$_[0]}) {$n1=pop @{$_[0]}; $n2 = pop @{$_[1]};
unshift @sum, $n1 + $n2; unshift @product, $n1 * $n2; }
return \@sum, \@product;
}

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
============================================================ OUTPUT ==
To redirect STDOUT to a file (or any filehandle to another filehandle)
*STDOUT = *OUT; #great for debugging when output usually to file
======================================================================
To have output go through pager program:
$pager = $ENV{'PAGER'} || '/usr/bin/less'; #make SURE pager is OK
open (STDOUT, "| $pager"); # terminal output one page at a time!
======================================================================
To enable auto-flushing of output (ie, simulate no buffering):
select(STDERR); $| = 1; select(STDOUT); $| = 1;
======================================================================
Instead of: $answer = $var1 . func() . $var2; #concat together
$answer = "$var1 @{[ LIST EXPR ]} $var2"; #force 'scalar' if req'd
(ie, $foo = "uppercase"; print "here is @{[uc $foo]} text";)
#example too trivial; for this would use "Here is \U$foo\E text"
======================================================================
To print $number, but print a zero if the variable is undefined:
print $number || '0';
======================================================================
To pad text with spaces (or zeros) to make string "n" chars in length:
padding on RIGHT: sprintf("%-ns", $foo);
padding on LEFT: sprintf("%ns", $foo); #or ("%0nd") for zeros
======================================================================
To indent a "here document" in code but not in output:
($var = <<' HERE') =~ s/^\s+//gm; #allow HERE target to indent!
Lorem ipsum #Perl Cookbook 1ed p 23
dolor sit amet
HERE
======================================================================
To print a hash in a prettified way:
print map { "$_\t=>\t$hash{$_}\n" } sort keys %hash;

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
============================================================== MISC ==
To simulate UN*X `grep -v`
grep (!/foo/, @foo); #or (!/foo/i, @foo) to simulate `grep -vi`
======================================================================
To simulate UN*X `uniq` (create @uniq w/distinct members of @orig)
%seen=(); @uniq = grep{! $seen{$_}++} @orig;
======================================================================
Schwartzian Transform: For example, to sort /etc/passwd file by fields
print map { $_->[0] } #Randal (one l) Schwartz Rocks!!!
sort { $a->[1] <=> $b->[1] #numerically sort first by gid
|| $a->[2] <=> $b->[2] #numerically sort second by uid
|| $a->[3] cmp $b->[3] #alphabetic sort by loginID last
} map { [ $_, (split /:/)[3,2,0] ] } `cat /etc/passwd`;

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
========================================================= DATE/TIME==
To print current date in format "YYYY-MM-DD" (ISO 8601), ie SQL format
($day, $month, $year) = (localtime)[3,4,5]; #no modules
printf("%04d-%02d-%02d", $year+1900, $month+1, $day);
OR printf("%04d-%02d-%02d",
sub {($_[5]+1900,$_[4]+1,$_[3])}->(localtime)); #no temp vars
OR use POSIX qw/strftime/; print strftime "%Y-%m-%d", localtime;
OR use Time::localtime; $tm = localtime;
printf("%04d-%02d-%02d", $tm->year+1900, ($tm->mon)+1, $tm->mday);
OR use Date::Manip; print UnixDate(scalar localtime, "%Y-%m-%d");
======================================================================
To get the mtime (lmod) of a file:
$mtime = (stat $file)[9]; #epoch time (1065381040). [8] = atime.
OR $mtime = localtime ((stat ($file))[9]); # Wed Aug 11 12:07:44 2004
OR $mtime = sprintf("%04d-%02d-%02d", #ie, YYYY-MM-DD w/o modules
sub{($_[5]+1900,$_[4]+1,$_[3])}->(localtime((stat($file))[9])));
======================================================================
To set file mtime (w/o File::Touch)(UTC: timegen instead of timelocal)
use Time::Local;
$mtime = timelocal($sec, $min, $hours, $mday, $month, $year);
utime( (stat($file)[9]), $mtime, $file ); #must include atime

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
============================================ MULTI-DIMENSIONAL ARRAY==
ARRAY OF ARRAYS (ie, $cars[0][1] eq 'yellow';ALT SYNTAX: $car[0]->[1])
@cars =([qw/red yellow green/],[qw/ford chevy/],[qw/coupe sedan/]);
HASH OF ARRAYS (ie, $car{'col'}[1] eq 'yellow')
%cars = (col=>[qw/red yellow green/],
make=>[qw/ford chevy/],body=>[qw/coupe sedan/]);
HASH OF HASHES (ie, $org{sales}{boss} eq 'Sue')
%org = (sales=>{boss=>'Sue', peon=>'Rob'},
mailroom=>{boss=>'Joe', peon => 'Jane'});
ARRAY OF HASHES (ie, $org[0]{boss} eq 'Sue'; $org[1]{peon} eq 'Jane')
@org = ({boss=>'Sue', peon=>'Rob'}, {boss=>'Joe', peon => 'Jane'});

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
=========================================================== IO::ALL ==
IO::All module is great! Instead of:
open (IN,'<','./stuff')||die $!;local $/;my $stuff = <IN>;close IN;
DO use IO::All; my $stuff < io"./stuff"; #let IO::All do the work!

Other kewl things (per perldoc)
#FILES
$io = io 'file.txt'; # Create a new IO::All object
$contents = $io->all; # read everything (or ->slurp)
$contents = join '', $io->getlines; # Join the separate lines
$content > io('file.txt'); # Print to file(>> for append)
@lines = io('file.txt')->chomp->slurp; # Chomp as you slurp
@chunks = io('file.txt')->separator('xxx')->slurp; #alt record sep
#DIRS
$io = io('my/directory/'); # Create new DIRECTORY object
@contents = $io->all; # Get all contents of dir
@contents = @$io; # Directory as an array
@contents = values %$io; # Directory as a hash
#STAT
printf "%s %s %s\n", # Print name, uid and size of
$_->name, $_->uid, $_->size # contents of current dir
for io('.')->all;
print "$_\n" for sort # Use mtime method to sort all
{$b->mtime <=> $a->mtime} # files under current dir
io('.')->All_Files; # by recent modification time.
#EXTERNAL
io("myfile") > io->("ftp://store.org"); # Upload file via ftp
$html < io->http("www.google.com"); # Grab a web page
io('mailto:[email protected]')->print($spam); # Email a "friend"
======================================================================
 
A

Ala Qumsieh

David said:
To set a variable to the greater (larger) of two choices:
$var = ($a > $b) ? $a : $b;

I find this a bit more amusing, although less maintainable:

$var = [$b => $a] -> [$b <= $a];
To replace $foo with $bar across an array
print s/$foo/$bar/ for @list #ie, void context

why print?

s/$foo/$bar/ for @list;

--Ala
 
D

David Filmer

Ala> I find this a bit more amusing, although less maintainable:
Ala>
Ala> $var = [$b => $a] -> [$b <= $a];

Yes, very amusing! I've never seen syntax like that before. Would you
be so kind as to explain this?
 
J

Jeff 'japhy' Pinyan

Ala> $var = [$b => $a] -> [$b <= $a];

Yes, very amusing! I've never seen syntax like that before. Would you
be so kind as to explain this?

[$b => $a] is an array reference with two elements, $a and $b. The => is
nothing more than a comma.

$var = [$b,$a]->[$b <= $a];

[$b,$a]->[...] is taking an element FROM that array reference. This could
be written, in this case, as a list and a list slice:

($b,$a)[...]

The contents of the slice are '$b <= $a', which is a comparison
expression, "$b less-than-or-equal-to $a". This comparison returns 1 if
$b is less than or equal to $a, and '' (which is as good as 0 here) if $b
is greater than $a.

($b,$a)[1] returns $a, and ($b,$a)[0] returns $b. So, if $a is greater
than $b, $a is returned; if $b is greater than $a, $b is returned. This
is a nearly palindromic max() expression.

--
Jeff "japhy" Pinyan % How can we ever be the sold short or
RPI Acacia Brother #734 % the cheated, we who for every service
RPI Corporation Secretary % have long ago been overpaid?
http://japhy.perlmonk.org/ %
http://www.perlmonks.org/ % -- Meister Eckhart
 
J

John W. Krahn

David said:
Ala> I find this a bit more amusing, although less maintainable:
Ala>
Ala> $var = [$b => $a] -> [$b <= $a];

Yes, very amusing! I've never seen syntax like that before. Would you
be so kind as to explain this?

It's very simple. :) You have a list with two elements ( $b, $a )
and you use a list slice to pick the correct one so when $b <= $a you
get ( $b, $a )[ 1 ] and when $b > $a you get ( $b, $a )[ 0 ]. Then
you throw in an anonymous array and dereference it and you get either
[ $b, $a ]->[ 1 ] or [ $b, $a ]->[ 0 ].


John
 
A

Abhinav

John said:
David said:
Ala> I find this a bit more amusing, although less maintainable:
Ala>
Ala> $var = [$b => $a] -> [$b <= $a];

Yes, very amusing! I've never seen syntax like that before. Would you
be so kind as to explain this?


It's very simple. :)

So it is .. once Its been explained :)

<OT>
Sherlock Holmes was always upset that Dr. Watson used to be initially
amazed at his deductions, but once he explained it, Dr Watson found them
outrageously "elementary" :)
</OT>
 
A

Ala Qumsieh

Jeff said:
This is a nearly palindromic max() expression.

I tried hard to make symmetric, to no avail. min() is palindromic though:

[$a => $b] -> [$b <= $a]

--Ala
 
R

Randal L. Schwartz

Ala> I find this a bit more amusing, although less maintainable:

Ala> $var = [$b => $a] -> [$b <= $a];

And more expensive. All the work to create an anonymous list, then an
anonymous array from that, take a reference to it, dereference it, and
then pull one of the two items back out, and then discard the array
and the list value.

Ugh.

Please shoot the person who came up with that cute hack. That's
just as cutesey (and dangerous) as rename $x => $y. Ugh.

print "Just another Perl hacker,";
 
J

Jeff 'japhy' Pinyan

Jeff said:
This is a nearly palindromic max() expression.

I tried hard to make symmetric, to no avail. min() is palindromic though:

[$a => $b] -> [$b <= $a]

Well, that's only palindromic if $a, $b, and -> are taken as individual
symbols, and if you let mirror image characters be palindromic of their
original.

--
Jeff "japhy" Pinyan % How can we ever be the sold short or
RPI Acacia Brother #734 % the cheated, we who for every service
RPI Corporation Secretary % have long ago been overpaid?
http://japhy.perlmonk.org/ %
http://www.perlmonks.org/ % -- Meister Eckhart
 
J

Jeff 'japhy' Pinyan

Please shoot the person who came up with that cute hack. That's
just as cutesey (and dangerous) as rename $x => $y. Ugh.

What, specifically, is dangerous about

rename $x => $y;

Apart from a lack of error-checking, I mean. I thought that was a rather
clever use of the => comma to signify a "becoming" relationship.

--
Jeff "japhy" Pinyan % How can we ever be the sold short or
RPI Acacia Brother #734 % the cheated, we who for every service
RPI Corporation Secretary % have long ago been overpaid?
http://japhy.perlmonk.org/ %
http://www.perlmonks.org/ % -- Meister Eckhart
 
A

Anno Siegel

Randal L. Schwartz said:
Ala> I find this a bit more amusing, although less maintainable:

Ala> $var = [$b => $a] -> [$b <= $a];

And more expensive. All the work to create an anonymous list, then an
anonymous array from that, take a reference to it, dereference it, and
then pull one of the two items back out, and then discard the array
and the list value.

Ugh.

Please shoot the person who came up with that cute hack. That's
just as cutesey (and dangerous) as rename $x => $y. Ugh.

Hey, it's a joke. I don't think anyone is suggesting it in earnest.
Not that a warning isn't in place, once it has appeared on Usenet.

However, the related

sub min { $_[ $_[ 1] < $_[ 0]] }

doesn't have unnecessary overhead. It is in fact quite fast, and
I have used it occasionally.

Anno
 
R

Randal L. Schwartz

Jeff> What, specifically, is dangerous about

Jeff> rename $x => $y;

Jeff> Apart from a lack of error-checking, I mean. I thought that was a rather
Jeff> clever use of the => comma to signify a "becoming" relationship.

Because it breaks as a general pattern. Witness:

use constant INCOMING => "/tmp/incoming.file.txt";
...
rename INCOMING => $new or die "Cannot rename ... ";

The problem is that once you start showing the pattern, the newbies
will combine it, not realizing that a fat arrow autoquotes the left
arg. Ooops. Cargoculting breaking things again.

So, don't use it. Or put a big warning on the right "use at your own
risk - your milage may vary".

print "Just another Perl hacker,";
 
J

Jeff 'japhy' Pinyan

The following is an excerpt from "Effective Perl Programming"
(Addison-Wesley; p.245):

[ $a => $b ] -> [ $b <= $a ]

I *thought* I remembered seeing that idiom in EPP. I'm just nowhere near
my copy to check.

--
Jeff "japhy" Pinyan % How can we ever be the sold short or
RPI Acacia Brother #734 % the cheated, we who for every service
RPI Corporation Secretary % have long ago been overpaid?
http://japhy.perlmonk.org/ %
http://www.perlmonks.org/ % -- Meister Eckhart
 
R

Randal L. Schwartz

Tim> I think we know which author contributed the word "wonderfully" to that
Tim> paragraph now, eh? ;-)

Yes, wasn't me. :)
 
G

Greg Bacon

: The problem is that once you start showing the pattern, the newbies
: will combine it, not realizing that a fat arrow autoquotes the left
: arg. Ooops. Cargoculting breaking things again.

I'm not convinced that this argument holds water. Is there *any*
feature of Perl that withstands this "look what the cargocultists
might do" test?

Greg
 
C

Charles DeRykus

Jeff> What, specifically, is dangerous about

Jeff> rename $x => $y;

Jeff> Apart from a lack of error-checking, I mean. I thought that was
Jeff> a rather clever use of the => comma to signify a "becoming"
Jeff> relationship.

Because it breaks as a general pattern. Witness:

use constant INCOMING => "/tmp/incoming.file.txt";
...
rename INCOMING => $new or die "Cannot rename ... ";

The problem is that once you start showing the pattern, the newbies
will combine it, not realizing that a fat arrow autoquotes the left
arg. Ooops. Cargoculting breaking things again.

Maybe suprising but true ...

use B::Deparse;
use constant FOO => "foo";
use strict;
use warnings;
print B::Deparse->new->coderef2text( sub {rename FOO => "bar"} );

output:

{
rename 'FOO', 'bar';
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top