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"
======================================================================
(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"
======================================================================