Some explanation please -- iterating thru command line arguments

--000325572daaa21957048be8fa79
Content-Type: text/plain; charset=ISO-8859-1

Hi all especially Perl teachers if anyone is ... :-)

I just want to know if someone can provide some explanation on how does the
argument iterator sub-routine below work. The Perl script is called from a
UNIX Korn script as below:

mail_smtp.pl -r ${MAILFROM} -s "$subject_line TEST EMAIL"
supportmail [at] test.com < /tmp/test_email.txt

The Perl script is working and SMTP mail is working. Am just trying to
understand how the getval sub-routine is parsing the command line arguments.
the getval subroutine is as below.

============================================================ =====

sub getval {
my $refVal = '';
foreach $var( [at] ARGV) {
if ($refVal ne '') {
$$refVal = $var;
$refVal = '';
}
else {
$_ = $var;
if (/-r/ ) {
$refVal=\$fromUser;
}
elsif (/-f/) {
$refVal=\$dataFile;
}
elsif (/-s/) {
$refVal=\$subject;
}
else {
[at] toUser = split(/[\;,]/,$var);
}

}
}
}

============================================================ =====

The portion that am confused at is at the following lines:

$$refVal = $var;

and

$_ = $var;
if (/-r/ ) {
$refVal=\$fromUser;
}

Does "if (/-r/ )" means "ignore" all command line that begins with a hyphen
but reference by value the next command line argument after them?

Does $_ contains the following values on each iteration?

mail_smtp.pl
-r
${MAILFROM}
-s
"$subject_line TEST EMAIL"
supportmail [at] test.com
<
/tmp/test_email.txt

Any "explanation" on this will be very much appreciated. Am going nuts
trying to understand how the iteration functions although am glad it is
functioning.

Thanks in advance.


===============================
mail_smtp.pl source code below:
===============================

#!/usr/bin/perl -w
use Net::SMTP;
use FileHandle;


# global variables
my $fromUser = $ENV{USER};
my [at] toUser = {};
my $smtpSvr = '192.168.3.11';
my $subject = '';
my $dataFile = '';
#$mailBody = '';
sub getval {
my $refVal = '';
foreach $var( [at] ARGV) {
if ($refVal ne '') {
$$refVal = $var;
$refVal = '';
}
else {
$_ = $var;
if (/-r/ ) {
$refVal=\$fromUser;
}
elsif (/-f/) {
$refVal=\$dataFile;
}
elsif (/-s/) {
$refVal=\$subject;
}
else {
[at] toUser = split(/[\;,]/,$var);
}

}
}
}

# main
getval( [at] ARGV);
if ( [at] toUser ne {}) {

if ($dataFile eq '') {
$dataFile = '-';
}
open(my $inFile, "< $dataFile");
$smtp = Net::SMTP->new($smtpSvr);
$smtp->mail($fromUser);
$smtp->to( [at] toUser);
$smtp->data();
$smtp->datasend("From:$fromUser\n");
$smtp->datasend("To:".join(';', [at] toUser)."\n");
if ($subject ne '') {
$smtp->datasend("Subject:$subject\n");
}
while (<$inFile>) {
if (/^\.$/) {
last;
}
else {
$smtp->datasend($_);
}

}
close($inFile);
$smtp->dataend();
$smtp->quit;
}

--000325572daaa21957048be8fa79--
newbie01 perl [ Mi, 21 Juli 2010 19:17 ] [ ID #2044897 ]

Re: Some explanation please -- iterating thru command line arguments

On 7/21/10 Wed Jul 21, 2010 10:17 AM, "newbie01 perl"
<newbie01.perl [at] gmail.com> scribbled:

> Hi all especially Perl teachers if anyone is ... :-)
>
> I just want to know if someone can provide some explanation on how does the
> argument iterator sub-routine below work. The Perl script is called from a
> UNIX Korn script as below:
>
> mail_smtp.pl -r ${MAILFROM} -s "$subject_line TEST EMAIL"
> supportmail [at] test.com < /tmp/test_email.txt
>
> The Perl script is working and SMTP mail is working. Am just trying to
> understand how the getval sub-routine is parsing the command line arguments.
> the getval subroutine is as below.
>
> ============================================================ =====
>
> sub getval {
> my $refVal = '';
> foreach $var( [at] ARGV) {
> if ($refVal ne '') {
> $$refVal = $var;
> $refVal = '';
> }
> else {
> $_ = $var;
> if (/-r/ ) {
> $refVal=\$fromUser;
> }
> elsif (/-f/) {
> $refVal=\$dataFile;
> }
> elsif (/-s/) {
> $refVal=\$subject;
> }
> else {
> [at] toUser = split(/[\;,]/,$var);
> }
>
> }
> }
> }
>
> ============================================================ =====
>
> The portion that am confused at is at the following lines:
>
> $$refVal = $var;

That line assigns (copies) the contents of the $var variable to the location
referenced by the $refVal pointer. This will be either $fromUser, $dataFile,
or $subject, depending upon the option entered (-r, -f, or -s,
respectively).

>
> and
>
> $_ = $var;
> if (/-r/ ) {
> $refVal=\$fromUser;
> }

The above lines copy the contents of $var to $_, tests if $_ contains the
string '-r', and, if it does, sets $refVal to 'refer' to $fromUser.

A better form would be to test $var directly:

if( $var =~ /-r/ ) {
$refVal = \$fromUser;
}

> Does $_ contains the following values on each iteration?

$var, and hence $_ (since it is a copy of $var), will contain the elements
of the [at] ARGV array, one per iteration of the foreach loop.

If you use the GetOptions module, you can replace the getval subroutine with
something like this (untested):

use Getopt::Long;

GetOptions(
'r=s' => \$fromUser,
'f=s' => \$dataFile,
's=s' => \$subject
);
push( [at] toUser, split/[;,]/) for [at] ARGV;



--
To unsubscribe, e-mail: beginners-unsubscribe [at] perl.org
For additional commands, e-mail: beginners-help [at] perl.org
http://learn.perl.org/
Jim Gibson [ Mi, 21 Juli 2010 20:55 ] [ ID #2044899 ]

Re: Some explanation please -- iterating thru command line arguments

newbie01 perl wrote:
> Hi all especially Perl teachers if anyone is ... :-)
>
> I just want to know if someone can provide some explanation on how does the
> argument iterator sub-routine below work. The Perl script is called from a
> UNIX Korn script as below:
>
> mail_smtp.pl -r ${MAILFROM} -s "$subject_line TEST EMAIL"
> supportmail [at] test.com< /tmp/test_email.txt
>
> The Perl script is working and SMTP mail is working. Am just trying to
> understand how the getval sub-routine is parsing the command line arguments.
> the getval subroutine is as below.
>
> ============================================================ =====
>
> sub getval {
> my $refVal = '';
> foreach $var( [at] ARGV) {
> if ($refVal ne '') {
> $$refVal = $var;
> $refVal = '';
> }
> else {
> $_ = $var;
> if (/-r/ ) {
> $refVal=\$fromUser;
> }
> elsif (/-f/) {
> $refVal=\$dataFile;
> }
> elsif (/-s/) {
> $refVal=\$subject;
> }
> else {
> [at] toUser = split(/[\;,]/,$var);
> }
>
> }
> }
> }
>
> ============================================================ =====
>
> The portion that am confused at is at the following lines:
>
> $$refVal = $var;
>
> and
>
> $_ = $var;
> if (/-r/ ) {
> $refVal=\$fromUser;
> }

When [at] ARGV is at the '-r' element the $refVal=\$fromUser assigns a
reference from $fromUser to the variable $refVal and then the next time
through the loop when [at] ARGV is the element just past '-r' $fromUser is
dereferenced through $$refVal and is assigned the current element of [at] ARGV.

You are probably better off just using Getopt::Std


> Does "if (/-r/ )" means "ignore" all command line that begins with a hyphen
> but reference by value the next command line argument after them?

In this case "if (/-r/ )" is just short for "if ($var =~ /-r/ )" but for
some "cute" reason the programmer decided to use $_ instead of $var.

Also, /-r/ matches the string '-r' *anywhere* in $_, not just at the
beginning. It would more properly be written as "if (/\A-r\z/ )" or
even "if ( $_ eq '-r' )".


> Does $_ contains the following values on each iteration?
>
> mail_smtp.pl
> -r
> ${MAILFROM}
> -s
> "$subject_line TEST EMAIL"
> supportmail [at] test.com
> <
> /tmp/test_email.txt
>
> Any "explanation" on this will be very much appreciated. Am going nuts
> trying to understand how the iteration functions although am glad it is
> functioning.
>
> Thanks in advance.
>
>
> ===============================
> mail_smtp.pl source code below:
> ===============================
>
> #!/usr/bin/perl -w

use warnings;
use strict;

> use Net::SMTP;
> use FileHandle;
>
>
> # global variables
> my $fromUser = $ENV{USER};
> my [at] toUser = {};

This is assigning a hash reference to the first element of [at] toUser which
makes little sense.


> my $smtpSvr = '192.168.3.11';
> my $subject = '';
> my $dataFile = '';
> #$mailBody = '';
> sub getval {
> my $refVal = '';
> foreach $var( [at] ARGV) {
> if ($refVal ne '') {
> $$refVal = $var;
> $refVal = '';
> }
> else {
> $_ = $var;
> if (/-r/ ) {
> $refVal=\$fromUser;
> }
> elsif (/-f/) {
> $refVal=\$dataFile;
> }
> elsif (/-s/) {
> $refVal=\$subject;
> }
> else {
> [at] toUser = split(/[\;,]/,$var);
> }
>
> }
> }
> }
>
> # main
> getval( [at] ARGV);

This is passing the array [at] ARGV to the [at] _ array inside the subroutine
but you don't use the [at] _ array inside the subroutine so why do it?


> if ( [at] toUser ne {}) {

That statement is useless and doesn't do what the programmer seems to
think it is doing. An array in scalar context will return the number of
elements in the array, which at this point is 1. So '1' will be
compared to the textual representation of an anonymous hash which is
something like 'HASH(0x9ec8818)' and the two will *never* be equal.

Even if the programmer just compared the first element of [at] toUser to an
anonymous hash they would *never* be equal.

What the programmer should have done is define the array without any
elements:

my [at] toUser;

And then test the array is scalar context to see if getval() populated
the array:

if ( [at] toUser ) {


> if ($dataFile eq '') {
> $dataFile = '-';
> }
> open(my $inFile, "< $dataFile");

You should *always* verify that the file was opened correctly before
using its filehandle.


> $smtp = Net::SMTP->new($smtpSvr);
> $smtp->mail($fromUser);
> $smtp->to( [at] toUser);
> $smtp->data();
> $smtp->datasend("From:$fromUser\n");
> $smtp->datasend("To:".join(';', [at] toUser)."\n");
> if ($subject ne '') {
> $smtp->datasend("Subject:$subject\n");
> }
> while (<$inFile>) {
> if (/^\.$/) {
> last;
> }
> else {
> $smtp->datasend($_);
> }
>
> }
> close($inFile);
> $smtp->dataend();
> $smtp->quit;
> }



John
--
Any intelligent fool can make things bigger and
more complex... It takes a touch of genius -
and a lot of courage to move in the opposite
direction. -- Albert Einstein

--
To unsubscribe, e-mail: beginners-unsubscribe [at] perl.org
For additional commands, e-mail: beginners-help [at] perl.org
http://learn.perl.org/
jwkrahn [ Mi, 21 Juli 2010 21:26 ] [ ID #2044903 ]

Re: Some explanation please -- iterating thru command line arguments

On Wed, Jul 21, 2010 at 1:17 PM, newbie01 perl <newbie01.perl [at] gmail.com> wrote:
> Does $_ contains the following values on each iteration?
>
> mail_smtp.pl
> -r
> ${MAILFROM}
> -s
> "$subject_line TEST EMAIL"
> supportmail [at] test.com
> <
> /tmp/test_email.txt

Just to clarify the end of the command line:

mail_smtp.pl -r ${MAILFROM} \
-s "$subject_line TEST EMAIL" \
supportmail [at] test.com < /tmp/test_email.txt

The '< /tmp/test_email.txt' part is not extra arguments passed to the
script. That is a file redirection operator in the shell[1], used to
write the file to the script's standard input stream. The script
accepts an option -f to specify the file to retrieve the message data
from, but if none is specified then it defaults to - which is
basically an alias for STDIN.[2]

The same thing can be accomplished with a pipe:

cat /tmp/test_email.txt | mail_smtp.pl -r ${MAILFROM} \
-s "$subject_line TEST EMAIL" supportmail [at] test.com

So the script wouldn't see arguments equal to '<' or
'/tmp/test_email.txt'. The shell will handle those for it automatically.


[1] http://en.wikipedia.org/wiki/Redirection_(computing)
[2] perldoc -f open

--
Brandon McCaig <bamccaig [at] gmail.com>
V zrna gur orfg jvgu jung V fnl. Vg qbrfa'g nyjnlf fbhaq gung jnl.
Castopulence Software <http://www.castopulence.org/> <bamccaig [at] castopulence.org>

--
To unsubscribe, e-mail: beginners-unsubscribe [at] perl.org
For additional commands, e-mail: beginners-help [at] perl.org
http://learn.perl.org/
Brandon McCaig [ Do, 22 Juli 2010 18:53 ] [ ID #2044990 ]

Re: Some explanation please -- iterating thru command line arguments

--0016e644df0acc5e19048c18c556
Content-Type: text/plain; charset=ISO-8859-1

Hi Brandon,

Thanks ... using the cat and pipe looks "cleaner" ... I will try that one
.... thanks

On Fri, Jul 23, 2010 at 4:53 AM, Brandon McCaig <bamccaig [at] gmail.com> wrote:

> On Wed, Jul 21, 2010 at 1:17 PM, newbie01 perl <newbie01.perl [at] gmail.com>
> wrote:
> > Does $_ contains the following values on each iteration?
> >
> > mail_smtp.pl
> > -r
> > ${MAILFROM}
> > -s
> > "$subject_line TEST EMAIL"
> > supportmail [at] test.com
> > <
> > /tmp/test_email.txt
>
> Just to clarify the end of the command line:
>
> mail_smtp.pl -r ${MAILFROM} \
> -s "$subject_line TEST EMAIL" \
> supportmail [at] test.com < /tmp/test_email.txt
>
> The '< /tmp/test_email.txt' part is not extra arguments passed to the
> script. That is a file redirection operator in the shell[1], used to
> write the file to the script's standard input stream. The script
> accepts an option -f to specify the file to retrieve the message data
> from, but if none is specified then it defaults to - which is
> basically an alias for STDIN.[2]
>
> The same thing can be accomplished with a pipe:
>
> cat /tmp/test_email.txt | mail_smtp.pl -r ${MAILFROM} \
> -s "$subject_line TEST EMAIL" supportmail [at] test.com
>
> So the script wouldn't see arguments equal to '<' or
> '/tmp/test_email.txt'. The shell will handle those for it automatically.
>
>
> [1] http://en.wikipedia.org/wiki/Redirection_(computing)
> [2] perldoc -f open
>
> --
> Brandon McCaig <bamccaig [at] gmail.com>
> V zrna gur orfg jvgu jung V fnl. Vg qbrfa'g nyjnlf fbhaq gung jnl.
> Castopulence Software <http://www.castopulence.org/> <
> bamccaig [at] castopulence.org>
>

--0016e644df0acc5e19048c18c556--
newbie01 perl [ Sa, 24 Juli 2010 04:18 ] [ ID #2045053 ]
Perl » gmane.comp.lang.perl.beginners » Some explanation please -- iterating thru command line arguments

Vorheriges Thema: File::Find usage
Nächstes Thema: sending control-D via perl/expect