The Sysadmin Notebook  

Sitemap

Perl Syntax Notes

Snippets of Perl Syntax to Insert Where Needed

Contents

Here Documents

Top Bottom

Here Documents allow you to process a block of text as an array of strings. Each line is an element of the array until the defined terminator is reached. The terminator is specified by a string immeadiately following two less than signs ('<<'). The block of text defined will interpolate according to whether the terminator is single, double-quoted or back-tick quoted. If unquoted, the block will behave as though the terminator was double-quoted.

use strict;
use warnings;

use Getopt::Long;

my ($commands, $help);
GetOptions(help => \$help, commands => \$commands);

&usage() unless $commands;

print <<`DONE`;
df -h
uptime
uname -a
DONE

sub usage() {
	print <<"EOF";
Description

\tThe System Administration Time-Saver

Synopsis

\t$0 -c

Options

\t$0 -h, --help\tPrints this message
\t$0 -c, --commands\tRuns the commands

EOF
exit;
}

The array of strings can be fed to print to provide multiline documentation, or used anywhere that an array of strings might be used:

use strict;
use warnings;

my @fruit = <<ENDFRUIT =~ m/(\S.*\S)/g;
	passion fruit
	avocado pear
	bannana
	kiwi fruit
	paw paw
ENDFRUIT

print "Found ", scalar(@fruit), " fruits\n";

Readline Operator

Top Bottom

The readline operator '<>' only assigns to $_ if it is the only condition in a while loop. At the end of the file '<>' returns undef, so check for defined rather than truth if assigning the line read. In scalar context, returns the next line in the file: in array context returns each line as a list element. Use '$.' to check the number of lines read so far by the script.

use strict;
use warnings;

use FindBin qw($Bin); 	# assigns path of script to $Bin

for my $file ( glob("$Bin/*.pl") ) {
	next unless open(INPUT, $file);
	print "$.] $_" while <INPUT>;
	$. = 0; 	#reset line number to zero for next file
}

Arrays

Top Bottom

The last index of an array is held in the special variable $#arrayname. The last element of an array can therefore be accessed as $arrayname[$#arrayname]. However it is also possible to write $arrayname[-1]. An array can be truncated, or extended by specifying a value for $#arrayname.

An array slice is specified as @arrayname['list literal']. An array slice will behave as a list literal in scalar context: returning its last element rather than a count of elements.

use strict;
use warnings;

use Test::More qw/no_plan/;

my @arr = qw(one two three four five six seven eight nine);
ok(scalar(@arr) == 9, "Number of elements in array");
ok($#arr == 8, "Index of last element");
ok($arr[$#arr] eq 'nine', "Last element in array via \$\#");
ok($arr[-1] eq 'nine', "Last element in array via -1");

my @evens = @arr[1,3,5,7];
my $count = @evens;
ok($count == 4, 'Array returns number of elements in scalar context');
my $last = @arr[1,3,5,7];
ok($last eq $evens[-1], 
	'Slice acts as a list literal in scalar context, 
	returning last element');
my ($first, undef, undef, $second) = @arr[1..4];
ok($first eq $arr[1], 'Elements assigned in left-right order in list context');
ok($second eq $arr[4], 'Unwanted elements can be assigned to undef');
$#arr = 3;
ok(scalar(@arr) == 4, "Truncate an array by assigning to \$\#");

Hashes

Top Bottom

Hashes are prefixed with a '%' sign and initialised with a list:

%sounds = (cat => 'meow', dog => 'bark', pig => 'oink', goldfish => 'undef')

Values are accessed via keys:

print "The $animal says " . $sounds{$animal};

use keys, values or each to iterate a hash:

foreach $key (keys %hash)
foreach $value (values %hash)
while (($nextkey, $nextval) = each %hash)

Subroutines

Top Bottom

Called by specifying their name, followed by a list of arguments:

@values = mysub (@args, @moreArgs);

The list of arguments can be empty, or omitted altogether, if the subroutine is defined before the call:

sub timefunc { return localtime() }
$timeval = timefunc;

The parentheses around the argument list can also be omitted if the the subroutine has been defined before the call:

@values = myfunc $first, $last;

Calling a subroutine with the '&' prefix but no argument list means is gets the current @_ argument list instead. This also happens when calling the subroutine with goto:

goto &mysub;

Named arguments can be provided to a subroutine using the '=>' notation when listing the arguments:

checkServer(name => 'server01', date => '-1', cols => 3);
sub checkServer {
	%defaults = (name => 'pdc01, date => '-5');
	#defaults get overwritten by argument list
	%args = (%defaults, @_);
	#another way to specify a default
	$args{cols} = 5 unless exists $args{cols};
	..
}

The calling context of a subroutine can be determined using the wantarray function:

use Carp;
sub variousReturns {
	# Do some processing here
	# true and defined
	return @someArray if wantarray;
	# false but defined
	return $someScalar if defined(wantarray);
	#false and not defined
	carp "subroutine &variousReturns was called in void context" unless(defined(wantarray));
}
Carp::carp reports the location of the call. Warn would report the location within the subroutine where the error occurred

The caller function returns a list of values indicating:

  1. the package from which the current subroutine was called
  2. the name of the file containing the code the called the current subroutine
  3. the line in that file from which the current subroutine was called
  4. the name of the subroutine
  5. whether the subroutine was passed arguments
  6. the context in which the subroutine was called
  7. the actual source code that called the subroutine, but only if the call was part of an eval TEXT statement
  8. whether the subroutine was called as part of a require or use statement

Reference and referents

Top Bottom

To create a reference use the unary '\' operator. References can be made to scalars, arrays, hashes, subroutines filehandles, patterns, typeglobs and other references. Use 'ref($myRef)' to determine type of a reference. Use the '->' operator to dereference a reference:

my $s = "A scalar value";
my @a = qw(a list of vaules);
my %h = (first => 1, second => 2, third => 3);
my ($slr_ref, $arr_ref, $hsh_ref, $sub_ref) = 
	(\$s, \@a, \%h, \&print_results);
$sub_ref->($slr_ref, $arr_ref, $hsh_ref, $sub_ref,);

($slr_ref, $arr_ref, $hsh_ref) = (\"Second scalar value",
	[qw(another list of values)], {fourth => 4, fifth => 5, sixth => 6});
$sub_ref->($slr_ref, $arr_ref, $hsh_ref);

print "Slice an array reference[", join(":", @$arr_ref[1,2]), "]\n";
print "Using arrow operator to access \$arr_ref->[1]: [$arr_ref->[1]]\n";
print "Using arrow notation to access \$hsh_ref->{fourth}: [$hsh_ref->{fourth}]\n";

my $matrix = [
		[1, 4, 7, 9],
		[2, 5, 8, 11],
		[3, 6, 9, 12],
	];
print "Element {2,3} of matrix is [$matrix->[1][2]]\n";

my $people = {
	John => { age => 60, height => 200, birthday => '1999-04-01'},
	Jill => { height => 180, sex => 'female', age => ''},
	Fred => { sex => 'male', telephone => '00234283434', height => 60},
};
print "John is ", $people->{John}{age}, " years old\n";

sub print_results() {
	my @args = @_;
	foreach my $arg (@args) {
		if (ref($arg) eq 'SCALAR') { print "${$arg}\n" }
		elsif (ref($arg) eq 'ARRAY') { print "@{$arg}\n" }
		elsif (ref($arg) eq 'HASH') {
			foreach my $key (keys %{$arg}) { print "$key => ${$arg}{$key}\n" }
		}
		elsif (ref($arg) eq 'CODE') { print "Got a subroutine reference\n" }
		else { print $arg, "\n" }
	}
}

Namespaces

Top Bottom

All variables exist in a namespace which is either global (defined in a package) or lexical (declared with 'my').

A symbol table or package is a global hash containing entries for global variables. To use a package variable outside the package namespace, prefix the variable with the name of the package and a double colon, or use a 'package' declaration to switch back to the package's namespace. A package declaration changes the namespace until another package declaration is encountered, or until the end of the current enclosing block.

Lexical variables must be defined with 'my', do not belong to any package and are only directly accessible within the defining code block. Lexical variables cease to exist outside the defining block unless some other part of the program has a reference to it. Lexical variables are not destroyed until their reference count is 0.

Local Variables

Top Bottom

The local function takes package variables and replaces their value until the end of the enclosing block. Subroutines called from within the block will see the temporary value of the variable.

Modules

Top Bottom

Modules are stored in .pm files, begin with a package declaration and end with '1;'. Version can be stored in $VERSION. Use the module with a 'use lib' statement to identify the modules location, and a 'use ModuleName' corresponding to the modules filename. Include version number as 'use ModuleName 1.20;'. Whenever a module is loaded, the modules 'import' subroutine is called with the name of the module plus any argument list that appears at the end of the module call. The 'import' subroutine is rarely used in OO perl.

Autoload

Top Bottom

If a non-existent package subroutine is called, perl will try to call the packages subroutine AUTOLOAD before issuing an error. AUTOLOAD is called with the argument list passed to the missing subroutine and the $AUTOLOAD variable is assigned the fully-qualified name of the missing subroutine.

# Do shell programming from perl
sub AUTOLOAD {
	$AUTOLOAD =~ s/.*:://;
	return `$AUTOLOAD @_`;
}

$network = ipconfig();
del('README.TXT');

Closures

Top Bottom

A closure is a subroutine that refers to one or more lexical variables declared outside the subroutines block. Lexical variables are scoped within their defining block: subroutines are not. Therefore lexical variables can be made accessible outside their defining block, via a subroutine defined within the block. The lexical variable can then be accessed outside its defining block via the subroutine. Closures allow you to set up variables that are private to the subroutines within the block defining the lexical variable:

{
	my $locked;

	sub lock { return 0 if $locked; $locked = 1};
	sub unlock { $locked = 0}
}
lock or die "Resource already in use";
# do some stuff
unlock();

Closures can be used to implement encapsulation.

Typeglobs

Top Bottom

A typeglob allows you to refer to all the symbol table entries for a particular package identifier. A typeglob is prefix with a '*' to indicate that it refers to all other types. Typeglobs do not apply to lexical variables, since they do not have a named symbol table. Assigning *bar to *foo, makes foo an alias for bar, and typeglob assignment forms the basis for module import/export operations. Individual entries in a symbol table can be assigned to another another typeglob using a reference as the rvalue.

package main;

$var = "The rain in Spain";
@var = qw( The rain in Spain);
%var = qw(The rain in Spain);

*newvar = *var;
print "The scalar in var is: [", $var, "]\n";
print "The scalar in newvar is: [", $newvar, "]\n";
print(join ":", @newvar, "\n");

*var = \"The sun in England";
print "The scalar in var is: [", $var, "]\n";
print "The scalar in newvar is: [", $newvar, "]\n";

$typeglob_ref = \*var;
print "The scalar in typeglob_ref is: [", ${*$typeglob_ref}, "]\n";
$slr_ref = *$typeglob_ref{SCALAR};
print "The scalar in slr_ref is: [", $$slr_ref, "]\n";

Symbolic references

Top Bottom

A symbolic reference is a character string containing the name of a variable or subroutine in a packages symbol table

package Utils;
sub formatter { print "Subroutine recieved '$_[0]' as first param\n"}
@formatter = qw(Yes that was lovely);
$formatter = ["no", "it", "wasn't"];

package main;
$symref = "Utils::formatter";
print "Here's the value of symref [$symref]\n";
print "Here's the symbolic reference to an array [@{$symref}] \n";

@{$symref}[0] = ${$symref}->[0];
print "After substituting from the scalar ref [", join(' ', @{$symref}), "]\n";

&{$symref}(${$symref}->[1]);