My own handy Pocket Reference notes (please share your own also)


D

David Filmer

Over the past couple of years, I have made many little notes inside
the covers of my O'Reilly Perl Pocket Reference - mostly syntax
hints/reminders from books and other usenet posts. I thought I would
post my notes here; maybe others can benefit (gurus probably less so).
Do you have some handy notes scratched inside YOUR Perl book? Maybe
you can share them also. Here are my personal quick reference notes
(in no particular order):
======================================================================
To redirect STDOUT to a file (or any filehandle to another filehandle)
*STDOUT = *OUT;
======================================================================
Instead of: $answer = $var1 . func() . $var2; #Perl CookBook 1ed p.21
$answer="$var1 ${\( SCALAR EXPR )} $var2"; #ie:"eat ${\($n+1)} pie"

$answer = "$var1 @{[ LIST EXPR ]} $var2";
(ie, $foo = "uppercase"; print "here is ${\( uc $foo )} text";)
OR (ie, $foo = "uppercase"; print "here is @{[uc $foo]} text";
======================================================================
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; (define $a as a substring of $b)
($b) = ($a =~ /foo(.*)/);
======================================================================
To strip leading/trailing spaces:
$foo =~ s/^\s+//; $foo =~ s/\s+$//;
======================================================================
To simulate UN*X `grep -v`
grep (!/foo/, @foo); #or (!/foo/i, @foo) to simulate `grep -vi`
======================================================================
To strip the path from a filename (such as $0) w/o File::Basename:
print ($0 =~ /^.\/(.*)/)[0];
======================================================================
To simulate UN*X `uniq` (create @uniq w/distinct members of @orig)
%seen=(); @uniq = grep{! $seen{$_}++} @orig;
======================================================================
To set a variable but only if it is currently undefined/zero/null:
$foo ||= 'bar';
======================================================================
To print $number, but print a zero if the variable is undefined:
print $number || '0';
======================================================================
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 = @_; }
======================================================================
To pass a hash from a subroutine (using references):
%foo = %{&MySubroutine()};
sub MySubroutine () { my $bar{'candy'}='chocolate'; return \%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"; #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 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 pass a filehandle (FH) the proper way, (for example with CGI.pm):
$foo = new CGI (\*FH);
======================================================================
To embed a variable in a variable name (maybe bad practice):
$foo = "foo"; print ${"${foo}bar"}; #same as ${'foobar'} or $foobar
======================================================================
To replace $foo with $bar across an array:
map {s/$foo/$bar/} @list; #no comma!
======================================================================
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 generate a random integer between 0 and 10 (inclusive):
$foo = rand(11); #or rand(10)+1 if between 1 and 10 inclusive
======================================================================
To print a hash in a prettified way:
print map { "$_\t=>\t$hash{$_}\n" } sort keys %hash;
======================================================================
To sort an array numerically (instead of Perl default alpha sort):
@sorted = sort { $a <=> $b } @unsorted; #Perl Cookbook 1ed p115
======================================================================
To prevent output from being buffered:
select(STDERR); $| = 1; select(STDOUT); $| = 1;
======================================================================
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!
======================================================================
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
directory
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"
======================================================================
Schwartzian Transform: For example, to sort /etc/passwd file by fields
print map { $_->[0] } #Randall Schwartz Rocks!!!
sort { $a->[1] <=> $b->[1] #numerically sort first by gid
|| $a->[2] <=> $b->[2] #numerically sort second by uid
|| $a->[3] <=> $b->[3] #alphabedic sort by loginID last
} map { [ $_, (split /:/)[3,2,0] ] } `cat /etc/passwd`;
======================================================================
To print current date in format "YYYY-MM-DD" (ISO 8601):
($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
======================================================================
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'});
======================================================================

Please feel free to make corrections or add your own! - DavidFilmer
 
Ad

Advertisements

T

Tad McClellan

David Filmer said:
Do you have some handy notes scratched inside YOUR Perl book? Maybe
you can share them also.

======================================================================
Instead of: $answer = $var1 . func() . $var2; #Perl CookBook 1ed p.21
$answer="$var1 ${\( SCALAR EXPR )} $var2"; #ie:"eat ${\($n+1)} pie"

$answer = "$var1 @{[ LIST EXPR ]} $var2";


I would prefer the original.

It isn't too painful and has much less potential for "startle factor".

I tend to format it so as to make it easy to see what's going on:

$answer = $var1
. func()
. $var2;
======================================================================
To embed a variable in a variable name (maybe bad practice):
^^^^^

The "maybe" is ill advised unless you are a Perl expert and know
why you must use symrefs this time.

Symref use can almost always be replaced with either a real
reference or with a hash data structure (or both).

======================================================================
To prevent output from being buffered:
select(STDERR); $| = 1; select(STDOUT); $| = 1;


To enable auto-flushing:
or
To simulate no buffering:

would be accurate.

$| does not disable buffering, it enable auto-flush. The filehandle
is still buffered (but the buffer gets flushed a lot more often).

(and STDERR is usually unbuffered anyway)

print map { $_->[0] } #Randall Schwartz Rocks!!!


He even named his company after rocks.

What a guy!


(but his name is spelled "Randal")
 
B

Bob Walton

David Filmer wrote:

....
======================================================================
Schwartzian Transform: For example, to sort /etc/passwd file by fields
print map { $_->[0] } #Randall Schwartz Rocks!!!
sort { $a->[1] <=> $b->[1] #numerically sort first by gid
|| $a->[2] <=> $b->[2] #numerically sort second by uid
|| $a->[3] <=> $b->[3] #alphabedic sort by loginID last
cmp-----------------------^^^


} map { [ $_, (split /:/)[3,2,0] ] } `cat /etc/passwd`;
======================================================================
....
 
B

Brian McCauley

David said:
Instead of: $answer = $var1 . func() . $var2; #Perl CookBook 1ed p.21
$answer="$var1 ${\( SCALAR EXPR )} $var2"; #ie:"eat ${\($n+1)} pie"

For the third time in 24 hours....

Please will people stop promulgating this broken constuct. I eventually
managed to get it withdrawn from perlfaq4 but it still seems to pop up a
lot.

${\(EXPR)} does not evaluate EXPR in a scalar context. It evaluates it
in a list context and then discards all but the last value. This is
actually a slight simplification - the context in which EXPR is not
quite a normal list context. (For details read about the \ operator).
$answer = "$var1 @{[ LIST EXPR ]} $var2";

Use this for scalars (actually single value lists) too. I realise
there's a slight overhead of creating a temporary array but I think the
gain in clarity is worth it. If you need to force a scalar context then
do so explicitly @{[ scalar EXPR ]}.
 
D

David Filmer

Thanks, Tad/Bob, for your input (and especially Bob for catching that
code error in the Schwartzian Transform! It was written correctly in
my book but transcribed incorrectly in my usenet post! OOPS!). I will
wait for other input and then post a corrected version per this input.
Additional notes are welcome!
 
D

David Filmer

OOPS, I just noticed another transcription error:
I didn't include the 'int' operator. This SHOULD say:

======================================================================
To generate a random integer between 0 and 10 (inclusive):
$foo = int rand(11); #or int rand(10)+1 between 1 and 10 inclusive
======================================================================

Again, I will wait for additional feedback and post corrected version.
 
Ad

Advertisements

A

Anno Siegel

David Filmer said:
Over the past couple of years, I have made many little notes inside
the covers of my O'Reilly Perl Pocket Reference - mostly syntax
[...]

To strip the path from a filename (such as $0) w/o File::Basename:
print ($0 =~ /^.\/(.*)/)[0];

This one doesn't compile, and the pattern is way off the mark.

print $0 =~ m{([^/]*)$}, "\n";

Anno
 
J

John W. Krahn

David said:
======================================================================
Instead of: $answer = $var1 . func() . $var2; #Perl CookBook 1ed p.21
$answer="$var1 ${\( SCALAR EXPR )} $var2"; #ie:"eat ${\($n+1)} pie"

$answer = "$var1 @{[ LIST EXPR ]} $var2";
(ie, $foo = "uppercase"; print "here is ${\( uc $foo )} text";)
OR (ie, $foo = "uppercase"; print "here is @{[uc $foo]} text";

That's a bit of overkill for uppercase (or lowercase):

$foo = "uppercase"; print "here is \U$foo\E text";)

======================================================================
To strip leading/trailing spaces:
$foo =~ s/^\s+//; $foo =~ s/\s+$//;

Or a bit more idiomatic:

s/^\s+//, s/\s+$// for $foo;

======================================================================
To replace $foo with $bar across an array:
map {s/$foo/$bar/} @list; #no comma!

What's wrong with one comma instead of two braces? :) Anyway, you should
use for instead of map in void context.

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




John
 
R

Randal L. Schwartz

David> print map { $_->[0] } #Randall Schwartz Rocks!!!

*Ahem* See headers or sig of this posting.
 
G

Glenn Jackman

At 2004-08-11 08:52PM said:
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 = @_; }

You don't want the "()" prototype and the &, unless you have read
perlsub thoroughly:

MySubroutine(%foo);
sub MySubroutine { my %bar = @_; }

although references are required if you need to pass more than one
hash/array:
myOtherSub(\%foo, \@bar, @baz);
sub myOtherSub {
my ($fooref, $barref, @baz) = @_;
#...
}
To pass a hash from a subroutine (using references):
%foo = %{&MySubroutine()};
sub MySubroutine () { my $bar{'candy'}='chocolate'; return \%bar; }

Similarly, without & and (prototype):
%foo = %{MySubroutine()};
sub MySubroutine { my $bar{'candy'}='chocolate'; return \%bar; }

or return the hash directly
%foo = mysub()
sub mysub {
#... create %bar
return %bar;
}
 
Ad

Advertisements

B

Brian McCauley

John said:
Or a bit more idiomatic:

s/^\s+//, s/\s+$// for $foo;


What's wrong with one comma instead of two braces?

Er, braces are more ideomatic. A block should look like a block.
Anyway, you should use for instead of map in void context.

Yes indeed.
 
B

Ben Morrow

Quoth Glenn Jackman said:
You don't want the "()" prototype and the &, unless you have read
perlsub thoroughly:

MySubroutine(%foo);
sub MySubroutine { my %bar = @_; }

....however, you will then need to predeclare the sub with 'use subs'.

use subs qw/MySubroutine/;

....

MySubroutine %foo; # no need for parens, either

....

sub MySubroutine { ... }

Also, it is worth noting that is is more usual in Perl circles to use
names_like_this than NamesLikeThis orLikeThis.

Ben
 
B

Brian McCauley

Ben said:
...however, you will then need to predeclare the sub with 'use subs'.

Wrong on two counts.

You only need to predeclare subroutines that are calee without () or
which have prototypes.

You can preclare with just

sub MySubroutine;

there is no need for the subs pragma.
 
Ad

Advertisements

Ad

Advertisements

J

J. Romano

Please feel free to make corrections or add your own! - DavidFilmer

Dear David,

I hope it's not too late to share my own, but here's one that I
picked up from reading O'Reilly's "Learning Perl" (the "llama book")
by Randal L. Schwartz and Tom Phoenix:

=================================
If you have a non-complex hash with unique values (as well as unique
keys), you can swap the keys and values with a call to the reverse()
function:

%states = (AZ => 'Arizona', CO => 'Colorado', NY => 'New York');
# Make the %abbr hash be the same as %states but
# with the keys and values swapped:
%abbr = reverse %states;
# Now %abbr is equivalent to:
# %abbr = (Arizona => 'AZ', Colorado => 'CO', 'New York' =>
'NY');
=================================

And here's another:

=================================
Normally, to compile and install a Perl module from CPAN on a Unix
system, you uncompress it and type:

perl Makefile.PL
make
make test

But this will usually only work if you have superuser access. Without
superuser access, you can still install it locally, and this is
normally done by replacing the "perl Makefile.PL" line with:

perl Makefile.PL PREFIX=/home_dir_path/perl_dir

(where /home_dir_path/perl_dir is the path to the directory where you
want your local perl modules installed). However, sometimes just
specifying PREFIX is not enough, and you must specify more parameters.
If this is the case, try the following line instead:

perl Makefile.PL \
PREFIX=/home_dir_path/perl_dir \
INSTALLPRIVLIB=/home_dir_path/perl_dir/lib/perl5 \
INSTALLSCRIPT=/home_dir_path/perl_dir/bin \
INSTALLSITELIB=/home_dir_path/perl_dir/lib/perl5/site_perl \
INSTALLBIN=/home_dir_path/perl_dir/bin \
INSTALLMAN1DIR=/home_dir_path/perl_dir/perl5/man \
INSTALLMAN3DIR=/home_dir_path/perl_dir/lib/perl5/man/man

Hopefully this will work if the previous line doesn't. Once you get
it working, don't forget to set your PERL5LIB environment variable to
/home_dir_path/perl_dir .
=================================

That's it for now. These notes were useful for me, so that's why I
included them here.

Have a good day!

-- Jean-Luc Romano
 

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

Top