Tips:
1. Getopt::Long
Getopt::Long module is used to parse both long and short options names. It's a replacement for Getopt::Std which only support single char options. The equivalent in Unix is getopt_long and getopt function.
Rules:
(1) Getopt won't force user to supply any option:
this means user can omit all options, and Getopt won't complain anything.
(2) Getopt only force the right format if options are supplied by user:
this means if user supplies options, the format must be right. (eg. it must have value or not)
(3) the default value is assigned by yourself in front of using GetOptions.
this means, you have to define variables used to hold the options' values first, and do initialization yourself if you want. Getopt don't supply any method to assign default values to these variables.
eg.
#!perl
use strict;
use Getopt::Long; # import the namespace
sub usage
{
print "$!";
print "Usage: read the code yourself:)";
exit(0);
}
# here we define variables and initializations. variables without initialization has "undefined" values.
my $o_help;
my $o_name = "sheep";
my $o_age = 10;
my @o_lib;
my %o_pair;
Getopt::Long::Configure(qw/no_auto_abbrev/); # we don't need abbrevation(eg. --hel for --help)
GetOptions('help|h' => \$o_help, # use | to supply alternative option names
'name=s' => \$o_name, # is = is used ,the option must has value. s indicate string
'age=i' => \$o_age, # is expected while i indicate integer is expected.
'lib=s' => \@o_lib, # use array if you have "--lib lib1 --lib lib2 --lib lib3"
'pair=s' => \%o_pair) or &usage(); # use hash if you have "--pair sheep=10 --pair cow=20
if (defined($o_help)) { # if user doesn't supply "help" option, the variable is undefined
print "o_help: $o_help\n";
}
if (defined($o_name)) {
print "o_name: $o_name\n";
}
if (defined($o_age)) {
print "o_age: $o_age\n";
}
if (defined(@o_lib)) {
print "o_lib: @o_lib\n";
}
if (defined(%o_pair)) {
print "o_pair: ", %o_pair, "\n";
}
2. how to print Usage: -- using Here Documents:
"here documents" is to prepare command/text lines needed at a time which're used by shell to feed the application one line each time the app needs input.
so it can be used to automatically interact with the interactive application.
eg.
sub usage
{
print(<<"USAGE"); # I can't believe print can use Here Document!!!
tellme Version:0.1, Copyright (C) 2009 ThomsonReuters.
the analysis result is stored in internal result_table.
the options given below is designed to print the table in various way.
and the default behavior is to output all kinds of tables.
Usage: tellme.pl <options>
--help
show this usage.
--raw-table
output the raw internal result_table.
--idn-non-enum-fields-table1 | -a
output all IDN's fields which are defined as non-enum type.
--idn-non-enum-fields-table2 | -b
output all IDN's fields which are defined in DB..xsd file as enum type,
but redefined in FieldType.xsd file as non-enum type.
--idn-equals-db-enum-table1 | -c
output all IDN's enum fields which have the same fields as db's.
--idn-equals-db-enum-table2 | -d
the simple version of --idn-equals-db-enum-table1.
--idn-unequals-db-enum-table1 | -e
output all IDN's enum fields which have different fields as db's.
--idn-unequals-db-enum-table2 | -f
the simple version of --idn-unequals-db-enum-table1.
--idn-enum-not-found-in-db | -g
output the IDN's enum fields which can not be found in db.
--verbose
output the header line.
USAGE
exit(0);
}
3. complex type - using hash and array
--- general rule: ---
(1) we can use "${}[]" to access elements of complex type:
eg. $hash{$key}[$i] # hash of array
$hash{$key}{key2} # hash of hash
(2) use @{} and %{} to indicate the content in {} is array or hash:
then you can use it as an array or hash name to refer to its elements use [] or {} as usual.
eg. we cat use them when list or hash is expected (eg. after "foreach"):
foreach my $value (@{$hash{$key}}) ... # @{} indicates $hash{$key} is an array
foreach my $key (keys %{$HoH{$login}}) ... # %{} indicates $HoH{$login} is a hash
--- use hash of hash: ---
eg. processing the /etc/passwd file
(1) create hash of hash:
my ( $login, $p, $uid, $gid, $gecos, $dir, $s );
my %HoH = ();
my $file = '/etc/passwd';
open( PASSWD, "< $file" ) or die "Can't open $file : $!";
while( <PASSWD> ) {
( $login, $p, $uid, $gid, $gecos, $dir, $s ) = split( ':' );
$HoH{ $login }{ 'uid' } = $uid;
$HoH{ $login }{ 'gid' } = $gid;
$HoH{ $login }{ 'dir' } = $dir;
}
close PASSWD;
yes, we have other style:
$HoH{$login} = { # NOTICE: { } must be used instead of () !!!!
"uid" => $uid,
"gid" => $gid,
"dir" => $dir
};
(2) access hash of hash:
method 1: you know the column name of sub hash.
foreach my $login ( keys %HoH ) {
$uid = $HoH{$login}{"uid"};
$gid = $HoH{$login}{"gid"};
$dir = $HoH{$login}{"dir"};
print "uid: $uid, gid: $gid, dir, $dir.\n";
}
method 2: you know nothing about the keys.
foreach my $login (keys %HoH) {
foreach my $key (keys %{$HoH{$login}}) {
print "$hash{$login}{$key}\n";
}
}
--- use hash of array ---
(1) create hash of array:
my %hash;
$hash{"one"} = [1, 2, 3]; # we use [] instead of () to construct list here !!!!
$hash{"two"} = ["cow", "cat", "sheep"];
(2) access hash of array:
method 1: you use foreach to access the array members.
foreach my $key (keys %hash) {
foreach my $value (@{$hash{$key}}) {
print "$value\n";
}
}
method 2: you wanna use index to access the array members.
foreach my $key (keys %hash) {
for (my $i = 0; $i < @{$hash{$key}}; $i++) {
print $hash{$key}[$i]."\n";
}
}
--- use array of array ---
(1) create array of array:
## we can use push or = to assign sub array into the array.
## NOTICE: we use [] instead of () to construct list here !!!!
push @result_table, [ $key, "-", $value_count, "-" ];
$result_table[1] = [ 1, 2, 3, 4 ];
my @AoA = (
[ "fred", "barney" ],
[ "george", "jane", "elroy" ],
[ "homer", "marge", "bart" ],
);
for $i ( 1 .. 10 ) {
@tmp = somefunc($i);
$AoA[$i] = [ @tmp ];
}
(2) access array of array:
method 1: use foreach to access the subarrays:
foreach my $sub_array (@array) {
foreach my $value (@{$sub_array}) {
print "$value\n";
}
}
method 2: use index to access members:
for (my $i = 0; $i < @array; $i++) {
for (my $j = 0; $j < @{$array[$i]}; $j++) {
print "$array[$i][$j]\n";
}
}
method 3: mixture of foreach and index
foreach my $sub_array (@array) {
for (my $j = 0; $j < @{$sub_array}; $j++) {
print "@{$sub_array}[$j]\n";
}
}
4. loop control:
last = break;
next = continue;
redo = goto front;
5. popular function error check styles:
guild: $! seems always holds error msg for functions and system commands.It will remains the same if no more errors happen in the following function calling like error in POSIX C. $? only holds command return codes, but it will change in each function call to hold return code. and $@ only holds msg for fatal errors, ie. some functions or operations will cause your program to exit without giving you the chance to handle. In this case, only eval block can stop your program from exiting and store the error msg in $@. The mkpath below is an example. NOTICE: $@ only has msg for fatal errors(errors that cause your program to exit without giving you the ability to handle)
(1) "if + $!" or "or + $!"
if (! chdir "/etc") { # the function will return true if successfully returned.
die "cannot chdir to /etc: $!";
}
chdir "/etc" or die "cannot chdir to /etc: $!";
(2) $? contains the recent `` system() or pipe 's return status code (the number)
$result = `ls`;
print "return code: $?" if $?;
(3) eval + $@
my $path = "Yaf:/cow/sheep/cat/"; # incorrect path name
eval {
mkpath($path,0,0755);
};
print "mkpath error: $@" if $@;
6. platform-independent file/folder operations:
(1) to create embeded directories:
use File::Path;
my $path = "cow/sheep/cat/"; # create dirs under current dir
eval {
mkpath($path,0,0755);
};
print "mkpath error: $@" if $@;
(2) use File::Basename and File::Spec to cover :\ \ or / issues:
don't deal with :\ \ or / things yourself in file path processing, use functions provided by File::Basename and File::Spec module to cover all related issues.
(3) use File::Copy to copy files
copy("name_age.txt", "name.txt") or die "cannot copy: $!\n";
7. text process related:
(1) upper, lower case:
uc() to uppercase
lc() to lowercase
8. m//g will do match many times !!
eg.
my %last_name = /(\w+)\s+(\w+)/g; # store every pair of matching.
while( $line =~ /\(/g ) { $left++; } # find the count of '(' in current line
9. use modules:
if you put modules under Y:\lib\, say GPC\MLS\COMMON.pm, you should invoke perl like this:
perl -IY:\lib\ script.pl,
and in script.pl you should write like this:
use GPC::MLS::COMMON;