setting %ENV in a module

P

pgodfrin

Greetings,
So - I'd like to have a subroutine that reads a file with lines like:
export MYENVVAR=some_data and sets the hash $ENV{MYENVVAR}=some_data.
This part is easy....

I'd like to put that subroutine in a module so that I can use that
subroutine wherever I want to. I having problems with scoping - seems
the module subroutine sets the environment but then loses when control
is returned to the calling program. This part is hard.

Any thoughts?

pg
 
G

Gunnar Hjalmarsson

pgodfrin said:
So - I'd like to have a subroutine that reads a file with lines like:
export MYENVVAR=some_data and sets the hash $ENV{MYENVVAR}=some_data.
This part is easy....

I'd like to put that subroutine in a module so that I can use that
subroutine wherever I want to. I having problems with scoping - seems
the module subroutine sets the environment but then loses when control
is returned to the calling program.

I can't reproduce the problem you describe.

C:\home>type MyModules\ENVSet.pm
package MyModules::ENVSet;
$ENV{MYENVVAR}='Hello';
1;

C:\home>type test.pl
use MyModules::ENVSet;
print "$ENV{MYENVVAR}\n";

C:\home>test.pl
Hello

C:\home>
 
P

pgodfrin

I can't reproduce the problem you describe.

C:\home>type MyModules\ENVSet.pm
package MyModules::ENVSet;
$ENV{MYENVVAR}='Hello';
1;

C:\home>type test.pl
use MyModules::ENVSet;
print "$ENV{MYENVVAR}\n";

C:\home>test.pl
Hello

C:\home>

I got the same results as you - with your code. My other code is still
screwy - more on this tomorrow...
pg
 
J

Joost Diepenmaat

pgodfrin said:
I'd like to put that subroutine in a module so that I can use that
subroutine wherever I want to. I having problems with scoping - seems
the module subroutine sets the environment but then loses when control
is returned to the calling program. This part is hard.

I'm not sure if this applies to your problem, but tou may be unaware
that on most operating systems it's impossible to set the environment
for anything other than the "current process" (and any child processes
will then inherit the parent's environment).

In other words, if program A fork()s program B, and program B
changes its %ENV, program A will not see those changes. Neither will
program B see any changes in program A's environment made after B is
forked off.
 
P

pgodfrin

I'm not sure if this applies to your problem, but tou may be unaware
that on most operating systems it's impossible to set the environment
for anything other than the "current process" (and any child processes
will then inherit the parent's environment).

In other words, if program A fork()s program B, and program B
changes its %ENV, program A will not see those changes. Neither will
program B see any changes in program A's environment made after B is
forked off.

Yes I'm aware of this - I think this is a scoping issue. So program A
loads the modules, and then calls it to set the environment values. I
only care for the variables set during that process, and any other
from the calling program. However, certain variables get set and
others are not set exactly right....

I'll send some example code shortly...
pg
 
P

pgodfrin

....snip...
Yes I'm aware of this - I think this is a scoping issue. So program A
loads the modules, and then calls it to set the environment values. I
only care for the variables set during that process, and any other
from the calling program. However, certain variables get set and
others are not set exactly right....

I'll send some example code shortly...
pg

Well - here's the scoop. I believe this is not necessarily a scoping
issue, but one of understanding how perl interprets environment
variables. (or maybe how I interpret how... <grin>). It appears that
if one tries to set $ENV{VARNAME}="$ENV-VAR" (with or without quotes)
then the resulting hash value is the literal $ENV-VAR - perl is not
evaluating the scalar variable. (as opposed to use Env qw(VAR-NAME)
which permits using $VAR-NAME as a scalar variable in the subsequent
code).

I'm a little stumped as to why.

the input file (I'd like to be compatible with unix export statements.
I strip that out later)
export TMPTEST=/tmp
export TMPTOO=$TMPTEST

The simplified module:
package MymodSimp;
use Env;
Env::import;
my(@rvars,$l,$e,$v);
open RVARS,"/home/pgodfrin/perl/et/etfile" ;
@rvars=<RVARS>; close RVARS;
foreach (@rvars)
{
if (!/(^export)(\s+)\w+=/) { next;} # skips garbage
($l,$e,$v) = (/^(export\s+)(\w+)=(.+)/);
$ENV{$e}="$v";
}
$ENV{TMPTREE}='myliteral';
1;

The calling program:
[pgodfrin:~/perl/et]> cat envtest
#!/usr/bin/perl
use warnings;
no warnings 'once';
use Env;
Env::import;
use MymodSimp ;

$ENV{TMPFOUR}="$TMPTOO";
$ENV{TMPFIVE}=$ENV{TMPTEST};
print "TMPTEST: $ENV{TMPTEST}\n";
print "TMPTOO: $ENV{TMPTOO}\n";
print "TMPTREE: $ENV{TMPTREE}\n";
print "TMPFOUR: $ENV{TMPFOUR}\n";
print "TMPFIVE: $ENV{TMPFIVE}\n";

chdir("$TMPTEST") or die "Can't change dir to $TMPTEST\n";
print "Change to dir $TMPTEST:"; system("pwd"); print "\n";
chdir("$TMPTOO") or die "Can't change dir to $TMPTOO\n";
print "Change to dir $TMPTOO:"; system("pwd"); print "\n";
chdir("$TMPFIVE") or die "Can't change dir to $TMPFIVE\n";
print "Change to dir $TMPFIVE:"; system("pwd"); print "\n";

exit;

The execution.
[pgodfrin:~/perl/et]> envtest
TMPTEST: /tmp
TMPTOO: $TMPTEST
TMPTREE: myliteral
TMPFOUR: $TMPTEST
TMPFIVE: /tmp
Change to dir /tmp:/tmp

Can't change dir to $TMPTEST

So - setting $ENV{TMPTOO}="$TMPTEST" doesn't evaluate the variable.

I was hoping to be able to have a perl program that uses environment
variables via the use Env qw(yada-yada) construct, but also be able to
load the env vars from a file in the event the same perl program is
called via the crontab. There is a workaround for the crontab thing:
(. varfile; myperlpgm) - this will first source the varfile and any
env vars defined there will be available to myperlpgm via use Env
qw(yada-yada), but that doesn't seem very elegant. Another work around
is to create a wrapper for any perl program that is executed in the
crontab: 22 13 * * * run-job - where run-job is either a shell script
or a calling perl program which set's the variables, but that also
seem inelegant and has it's own set of problems). In any case, that's
the source of my consternation...

regards,
pg
 
J

Joost Diepenmaat

pgodfrin said:
the input file (I'd like to be compatible with unix export statements.
I strip that out later)
export TMPTEST=/tmp
export TMPTOO=$TMPTEST

The simplified module:

[ ... ]
($l,$e,$v) = (/^(export\s+)(\w+)=(.+)/);
$ENV{$e}="$v";

This is your problem.

Since you're TMPTOO=$TMPTEST is read from a file it's not
interpolated. You're effectively doing

my $e = 'TMPTOO';
my $v = '$TMPTEST';
$ENV{$e}=$v;

Also note that "$v" only interpolates the value of $v, not any $vars in
the value of $v. This is intentional, since otherwise reading from a
file or assigning strings would interpolate all over the place.

I'd do something like this:

my ($l,$e,$v) = (/^(export\s+)(\w+)=(.+)/);
$v = s/\$(\w+)/$ENV{$1}/eg; #look up $somethings in $ENV
$ENV{$e}=$v;

Note 2: this does not handle quotes in the export statement.
 
T

Tad J McClellan

($l,$e,$v) = (/^(export\s+)(\w+)=(.+)/);
$ENV{$e}="$v";


What values will those variables have if the string
in $_ does not happen to match your pattern?

if ( ($l,$e,$v) = (/^(export\s+)(\w+)=(.+)/) ) {
# do stuff with $l, $e and $v
}
 
P

pgodfrin

pgodfrin said:
Well - here's the scoop. I believe this is not necessarily a scoping
issue, but one of understanding how perl interprets environment
variables. (or maybe how I interpret how... <grin>). It appears that
if one tries to set $ENV{VARNAME}="$ENV-VAR" (with or without quotes)
then the resulting hash value is the literal $ENV-VAR - perl is not
evaluating the scalar variable. (as opposed to use Env qw(VAR-NAME)
which permits using $VAR-NAME as a scalar variable in the subsequent
code).

That is most definitely not true. You are extracting the string
'$TMPTEST' from a string using a regular expression and storing it into
the variable $v. When you assign the value of $v, using the expression
"$v", to the value of the %ENV hash, that string gets stored as is. If
you want to evaluate what $v contains as a Perl expression, then you
should use the eval operator:

$ENV{$e} = eval $v;

See the difference here:

% perl -e '$x=q($y);$y="abc";print $x,"\n";'
$y
% perl -e '$x=q($y);$y="abc";print eval $x,"\n";'
abc

The Env package (I have not used it) ties the values of the members of
%ENV to scalar variables (and arrays if needed), so it will tie
$ENV{TMPTEST} to $TMPTEST, and changing one will change the other.
Perhaps this fact is confusing you. If so, you might be better off not
using Env.pm and sticking to just using %ENV.




I'm a little stumped as to why.
the input file (I'd like to be compatible with unix export statements.
I strip that out later)
export TMPTEST=/tmp
export TMPTOO=$TMPTEST
The simplified module:
package MymodSimp;
use Env;
Env::import;
my(@rvars,$l,$e,$v);
open RVARS,"/home/pgodfrin/perl/et/etfile" ;
@rvars=<RVARS>; close RVARS;
foreach (@rvars)
{
if (!/(^export)(\s+)\w+=/) { next;} # skips garbage
($l,$e,$v) = (/^(export\s+)(\w+)=(.+)/);
$ENV{$e}="$v";
}
$ENV{TMPTREE}='myliteral';
1;

It is an inefficient use of memory to read a file into an array,
process the lines of that array one-at-a-time, and discard the array.
It is more efficient to process the lines when they are read.

There is no need to use two identical regular expressions to test for a
match and then extract data. Do it in one step.

It is better to use private variables for file handles and use the
three-argument version of open.

There is no need to quote scalar variables.

Therefore:

package MymodSimp;
open my $rvars, '<', "/home/pgodfrin/perl/et/etfile" ;
foreach (<$rvars>)
{
if( /^export\s+(\w+)=(.+)/ ) {
$ENV{$1}=$2;
}}

$ENV{TMPTREE}='myliteral';
1;


The calling program:
[pgodfrin:~/perl/et]> cat envtest
#!/usr/bin/perl

use strict;


use warnings;
no warnings 'once';
use Env;
Env::import;
use MymodSimp ;
$ENV{TMPFOUR}="$TMPTOO";
$ENV{TMPFIVE}=$ENV{TMPTEST};
print "TMPTEST: $ENV{TMPTEST}\n";
print "TMPTOO: $ENV{TMPTOO}\n";
print "TMPTREE: $ENV{TMPTREE}\n";
print "TMPFOUR: $ENV{TMPFOUR}\n";
print "TMPFIVE: $ENV{TMPFIVE}\n";
chdir("$TMPTEST") or die "Can't change dir to $TMPTEST\n";
print "Change to dir $TMPTEST:"; system("pwd"); print "\n";
chdir("$TMPTOO") or die "Can't change dir to $TMPTOO\n";
print "Change to dir $TMPTOO:"; system("pwd"); print "\n";
chdir("$TMPFIVE") or die "Can't change dir to $TMPFIVE\n";
print "Change to dir $TMPFIVE:"; system("pwd"); print "\n";

The execution.
[pgodfrin:~/perl/et]> envtest
TMPTEST: /tmp
TMPTOO: $TMPTEST
TMPTREE: myliteral
TMPFOUR: $TMPTEST
TMPFIVE: /tmp
Change to dir /tmp:/tmp
Can't change dir to $TMPTEST
So - setting $ENV{TMPTOO}="$TMPTEST" doesn't evaluate the variable.

It does, but that is not what you are doing. You are doing

$ENV{TMPTOO} = "$TMPTOO";

where $TMPTOO contains '$TMPTEST'.

--
Jim Gibson


----------------------------------------------------------

----------------------------------------------------------
color]

Hi - I knew there was a better way! I will try this out. I realized as
I was posting my code that it is indeed silly to dump the file into
memory. I've changed that. Why is the three argument version of open
better though?

thanks,
pg
 
B

Ben Morrow

Quoth Jim Gibson said:
It is more explicit and more flexible. See 'perldoc -f open' for all
the things you can do with the 3-argument version of open. For simple
programs, it doesn't really matter. But for more complicated programs,
the explicitness is helpful and consistency is good for
maintainability.

One slightly facetious difference: with 2-argument open you can't open
a file named '<stupid_file_name.txt'.

Much more importantly, if someone passes you a filename of
'rm -rf /; echo |' you won't delete all your files by mistake.

Ben
 
P

pgodfrin

Quoth Jim Gibson <[email protected]>:






Much more importantly, if someone passes you a filename of
'rm -rf /; echo |' you won't delete all your files by mistake.

Ben

Howdy - good advice all around. Now my code is really efficient, but
it still doesn't work <grin>

#!/usr/bin/perl
use Env;
open $rvars,"<","/home/pgodfrin/perl/et/etfile" ;
foreach(<$rvars>)
{
if (/^export\s+(\w+)=(.+)/)
{
$ENV{$1}=$2;
}
}
$ENV{TMPTREE}='myliteral';
foreach $key (sort(keys %ENV)) {
print $key, '=', $ENV{$key}, "\n";
}

results:

TMPTEST=/tmp
TMPTOO=$TMPTEST
TMPTREE=myliteral

I also tried what Joost suggested - nope...
Anyone test this?
pg
 
B

Ben Morrow

Quoth pgodfrin said:
Howdy - good advice all around. Now my code is really efficient, but
it still doesn't work <grin>

#!/usr/bin/perl

Where is

use warnings;
use strict;

You don't need this.
open $rvars,"<","/home/pgodfrin/perl/et/etfile" ;

*Always* check if open failed.
I would recommend using UPPERCASE variable names for filehandles.
I would put the filename in a variable, so you can easily find and
change it later.

my $Etfile = '/home/.../etfile';

open my $RCVARS, '<', $Etfile
or die "can't read $Etfile: $!";
foreach(<$rvars>)
{
if (/^export\s+(\w+)=(.+)/)
{

I would capture these into variables rather than using $N. Here you also
need to substitute for $vars in the replacement. This is a rather crude
version; it doesn't honour proper shell quoting, though it does allow \$
for a literal $. If you need real shell interpolation, it's probably
easiest to feed it to /bin/sh with 'exec /usr/bin/env' stuck on the end,
and parse the output.

if (my ($var, $value) = /^ export \s+ (\w+) = (.+)/x) {
for ($value) {
s/ (?<! \\ ) \$ (\w+) /$ENV{$1}/gx;
s/ \\ (.) /$1/gx;
}

Ben
 
P

pgodfrin

....snip...
I would capture these into variables rather than using $N. Here you also
need to substitute for $vars in the replacement. This is a rather crude
version; it doesn't honour proper shell quoting, though it does allow \$
for a literal $. If you need real shell interpolation, it's probably
easiest to feed it to /bin/sh with 'exec /usr/bin/env' stuck on the end,
and parse the output.

if (my ($var, $value) = /^ export \s+ (\w+) = (.+)/x) {
for ($value) {
s/ (?<! \\ ) \$ (\w+) /$ENV{$1}/gx;
s/ \\ (.) /$1/gx;
}

Ben

Hi Ben,
You da MAN! I still don't understand the "zero-width negative look-
behind assertion" you're using, nor anything about how that regular
expression works, but you've solved this problem (wow!):

Here are the results:
package Mymod;
use strict;
use warnings;
our ($VERSION, @ISA, @EXPORT, @EXPORT_OK);
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(setrun);

sub setrun
{
my($evf)=@_ ;
my($RVARS,$e,$v);
open $RVARS,"<","$evf" or die "Can't open input: $evf\n";
foreach (<$RVARS>)
{
if (($e,$v) = /^export\s+(\w+)=(.+)/)
{
for ($v)
{
s/(?<!\\)\$(\w+)/$ENV{$1}/g;
s/\\(.)/$1/g;
}
$ENV{$e}=$v;
}
} # end foreach
close $RVARS;
return 1;
} # end setenv
1;

#!/usr/bin/perl
use warnings;
no warnings 'once';
use Env;
#Env::import;
#use MymodSimp2 ;
use Mymod;
setrun("etfile");
print "TMPTEST: $ENV{TMPTEST}\n";
print "TMPTOO: $ENV{TMPTOO}\n";
print "Now with scalar vars...\n";
Env::import;
print "TMPTEST: $TMPTEST\n";
print "TMPTOO: $TMPTOO\n";
exit;

[pgodfrin:~/perl/et]> envtest
TMPTEST: /tmp
TMPTOO: /tmp
Now with scalar vars...
TMPTEST: /tmp
TMPTOO: /tmp

I'll try to figure out the RE but ... wow!

thanks,
pg
 
B

Ben Morrow

Quoth pgodfrin said:
Here are the results:
package Mymod;
use strict;
use warnings;
our ($VERSION, @ISA, @EXPORT, @EXPORT_OK);

Don't declare variables up-front like this. Perl isn't C or Pascal.
Declare them as you first need them.
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(setrun);

sub setrun
{
my($evf)=@_ ;

Your code will be much easier to follow if you indent properly.
my($RVARS,$e,$v);
open $RVARS,"<","$evf" or die "Can't open input: $evf\n";
foreach (<$RVARS>)
{
if (($e,$v) = /^export\s+(\w+)=(.+)/)

If you had used

if (my ($e, $v) = ...) {

as I originally had, $e and $v would be scoped to the 'if' statement. It
is always best to give variables as small a scope as you can.
{
for ($v)
{
s/(?<!\\)\$(\w+)/$ENV{$1}/g;
s/\\(.)/$1/g;

To expand these two a little more (note the use of /x, which allows
whitespace and comments in the 'pattern' part):

s/ # replace...

(?<! \\ ) # not immediately after a backslash
# (this prevents '\$foo' from being replaced)

\$ # a dollar sign

(\w+) # an identifier, which will be captured into $1

/$ENV{$1}/gx; # ...with the appropriate env var

s/ # replace...
\\ # a backslash, followed by
(.) # any character (captured into $1)
/$1/gx; # ...with that character (so \\->\, \$->$, etc.)

}
$ENV{$e}=$v;
}
} # end foreach

Decent indentation makes comments like this redundant.
close $RVARS;

Since you don't check the return value of close (not usually useful on
filehandles opened for reading, anyway), there's no point in explicitly
calling it. Just let the variable go out of scope, and Perl will close
it for you.
return 1;

There's no need for a return value like this that doesn't convey any
information to the caller. Falling off the end of a sub is a perfectly
respectable way to return (the return value will in fact be the value of
the last statement executed, but since you don't check it anyway that
doesn't matter). If you do want a 'null' return, a simple

return;

will return undef in scalar context and the empty list in list context,
which is usually appropriate.
} # end setenv
1;

#!/usr/bin/perl
use warnings;
no warnings 'once';
use Env;

I would recommend against using Env, unless you're a shell programmer
trying hard not to really learn Perl (which is OK, of course, but don't
expect a lot of sympathy from the people here :) ). Importing an
unspecified list of variables into your namespace just for the sake of
avoiding a hash lookup is not a good tradeoff. (Shell should be avoided
for much the same reason, neat though the idea is.) The fact that you
have to turn off 'once' warnings should alert you to the fact this is
not necessarily a good idea, though there are of course occasions where
turning off warnings is the right answer.
#Env::import;
#use MymodSimp2 ;
use Mymod;

You will find it makes your life easier later if you use explicit import
lists where practical. When you come to this code later, it makes it
much simpler to work out where setrun is defined if you can see it in
the 'use' line.

use Mymod qw/setrun/;

Also, I presume this is just an example, but you should *really* choose
a better name than 'Mymod'. I tend to use BMORROW::* for my own private
modules, so I'd call this something like BMORROW::SetEnv, which means it
would need to live in a file called SetEnv.pm in a directory BMORROW
somewhere in @INC.
setrun("etfile");
print "TMPTEST: $ENV{TMPTEST}\n";

If you set $\ (or use the -l switch on the #! line) Perl will add those
newlines for you. If you have 5.10 you can use 'say' instead of 'print'
for the same effect. Also, several lines of print statements usually
work better as a heredoc:

print <<ENV;
TMPTEST: $ENV{TMPTEST}
TMPTOO: $ENV{TMPTOO}
Now with scalar vars...
TMPTEST: $TMPTEST
ENV

See how much easier it is to get things lined up when you can see how
they will appear?
print "TMPTOO: $ENV{TMPTOO}\n";
print "Now with scalar vars...\n";
Env::import;

You do realise Env->import (which is subtly but importantly different
from Env::import) has already been called, at compile time, by the 'use'
statement? If it hadn't, the next two lines would never have got past
'use strict'.
print "TMPTEST: $TMPTEST\n";
print "TMPTOO: $TMPTOO\n";
exit;

Again, there's no need to explicitly exit unless you want to do so
early. Falling off the end of the program is a perfectly good way out.

Ben
 
P

pgodfrin

Quoth pgodfrin <[email protected]>:




Don't declare variables up-front like this. Perl isn't C or Pascal.
Declare them as you first need them.



Your code will be much easier to follow if you indent properly.


If you had used

if (my ($e, $v) = ...) {

as I originally had, $e and $v would be scoped to the 'if' statement. It
is always best to give variables as small a scope as you can.


To expand these two a little more (note the use of /x, which allows
whitespace and comments in the 'pattern' part):

s/ # replace...

(?<! \\ ) # not immediately after a backslash
# (this prevents '\$foo' from being replaced)

\$ # a dollar sign

(\w+) # an identifier, which will be captured into $1

/$ENV{$1}/gx; # ...with the appropriate env var

s/ # replace...
\\ # a backslash, followed by
(.) # any character (captured into $1)
/$1/gx; # ...with that character (so \\->\, \$->$, etc.)


Decent indentation makes comments like this redundant.


Since you don't check the return value of close (not usually useful on
filehandles opened for reading, anyway), there's no point in explicitly
calling it. Just let the variable go out of scope, and Perl will close
it for you.


There's no need for a return value like this that doesn't convey any
information to the caller. Falling off the end of a sub is a perfectly
respectable way to return (the return value will in fact be the value of
the last statement executed, but since you don't check it anyway that
doesn't matter). If you do want a 'null' return, a simple

return;

will return undef in scalar context and the empty list in list context,
which is usually appropriate.



I would recommend against using Env, unless you're a shell programmer
trying hard not to really learn Perl (which is OK, of course, but don't
expect a lot of sympathy from the people here :) ). Importing an
unspecified list of variables into your namespace just for the sake of
avoiding a hash lookup is not a good tradeoff. (Shell should be avoided
for much the same reason, neat though the idea is.) The fact that you
have to turn off 'once' warnings should alert you to the fact this is
not necessarily a good idea, though there are of course occasions where
turning off warnings is the right answer.


You will find it makes your life easier later if you use explicit import
lists where practical. When you come to this code later, it makes it
much simpler to work out where setrun is defined if you can see it in
the 'use' line.

use Mymod qw/setrun/;

Also, I presume this is just an example, but you should *really* choose
a better name than 'Mymod'. I tend to use BMORROW::* for my own private
modules, so I'd call this something like BMORROW::SetEnv, which means it
would need to live in a file called SetEnv.pm in a directory BMORROW
somewhere in @INC.


If you set $\ (or use the -l switch on the #! line) Perl will add those
newlines for you. If you have 5.10 you can use 'say' instead of 'print'
for the same effect. Also, several lines of print statements usually
work better as a heredoc:

print <<ENV;
TMPTEST: $ENV{TMPTEST}
TMPTOO: $ENV{TMPTOO}
Now with scalar vars...
TMPTEST: $TMPTEST
ENV

See how much easier it is to get things lined up when you can see how
they will appear?


You do realise Env->import (which is subtly but importantly different
from Env::import) has already been called, at compile time, by the 'use'
statement? If it hadn't, the next two lines would never have got past
'use strict'.


Again, there's no need to explicitly exit unless you want to do so
early. Falling off the end of the program is a perfectly good way out.

Ben

Hi Ben,
Thanks for the advice. Yes this is only example or testing code. And
thanks for explaining the RE - that helps a lot. I wasn't aware that
it was OK to permit file handles to close by going out of scope, nor
that it was ok to leave a routine without a return. I'll follow up on
that a little more, because I really do want to learn Perl better. I'm
neither a perl programmer, nor a shell script-er, but a DBA (since,
like, before there were relational databases!).

So essentially all I want to do is the DBA stuff, using perl instead
of shell, which is why you see me asking questions about environment
variables and executing processes in the background :).

In any case, the reason I predeclared the $VERSION and the @...
subroutines is because I saw that in an example in some discussion of
making perl modules. Could you suggest a definitive doc for creating
modules?

About the use Env and Env::import - my goal for these perl scripts
(programs?) was to make them executable from either the command line,
cron or some other scheduling package. So, I am indeed trying to avoid
a hash lookup, mostly for cosmetic's sake, but also for other DBA's
who have never seen perl and refuse to be brought into the [perl]
fold. It would be easier for them to see $mydir="$HOME" as opposed to
$mydir=$ENV{HOME}. However, I am in the habit of calling Env qw(HOME);
so as to minimize what I'm using.

But to be honest I really don't fully understand module coding and
"EXPORTing" and what the difference is between use Mymod and use Mymod
qw(setrun) really is. which is why I asked about a definitive doc for
that...

But all in all - thanks very, very much for your help and advice - and
anyway who needs your sympathy! <grin>

regards,
pg
 
B

Ben Morrow

Quoth pgodfrin said:
Thanks for the advice. Yes this is only example or testing code. And
thanks for explaining the RE - that helps a lot. I wasn't aware that
it was OK to permit file handles to close by going out of scope,

This only applies to lexical filehandles (those opened like

open my $FH, ...

) of course. Global filehandles (those opened like

open FH, ...

) never go out of scope.
So essentially all I want to do is the DBA stuff, using perl instead
of shell, which is why you see me asking questions about environment
variables and executing processes in the background :).

There's no problem with that :). Perl was designed for systems
administration, after all. If you get to the point of actually talking
to a database, you may want to check out the DBI module, which provides
an extremely flexible interface to practically every database there is
from Perl. It's often easier to use than trying to feed commands to the
database-provided utilities.
In any case, the reason I predeclared the $VERSION and the @...
subroutines is because I saw that in an example in some discussion of
making perl modules. Could you suggest a definitive doc for creating
modules?

Yes, there's an *awful* lot of bad Perl advice out there. A good place
to start is perldoc perlnewmod; you can ignore some of the advice that
assumes you will be uploading your module to CPAN (presumably you
won't), but from experience I would recommend packaging your modules up
into proper CPAN-style distributions. It's not hard, and the 'extra'
work you are prompted to do (writing documentation and tests) is well
worth doing anyway, and makes it much easier to install them on a new
machine, which inevitably turns out to be necessary :).
About the use Env and Env::import - my goal for these perl scripts
(programs?) was to make them executable from either the command line,
cron or some other scheduling package. So, I am indeed trying to avoid
a hash lookup, mostly for cosmetic's sake, but also for other DBA's
who have never seen perl and refuse to be brought into the [perl]
fold. It would be easier for them to see $mydir="$HOME" as opposed to
$mydir=$ENV{HOME}.

Really? I would have thought if they are unwilling to learn even that
much Perl there's little point them even trying to modify the scripts.
However, I am in the habit of calling Env qw(HOME); so as to minimize
what I'm using.

Yes, that is better.
But to be honest I really don't fully understand module coding and
"EXPORTing" and what the difference is between use Mymod and use Mymod
qw(setrun) really is. which is why I asked about a definitive doc for
that...

perldoc perlmod, and perldoc Exporter which that points you to. Note
that the code examples in perldoc Exporter, at least as of 5.8.8, do not
'use strict', which is against current best practices.

Ben
 
P

pgodfrin

Quoth pgodfrin <[email protected]>:


Thanks for the advice. Yes this is only example or testing code. And
thanks for explaining the RE - that helps a lot. I wasn't aware that
it was OK to permit file handles to close by going out of scope,

This only applies to lexical filehandles (those opened like

open my $FH, ...

) of course. Global filehandles (those opened like

open FH, ...

) never go out of scope.
So essentially all I want to do is the DBA stuff, using perl instead
of shell, which is why you see me asking questions about environment
variables and executing processes in the background :).

There's no problem with that :). Perl was designed for systems
administration, after all. If you get to the point of actually talking
to a database, you may want to check out the DBI module, which provides
an extremely flexible interface to practically every database there is
from Perl. It's often easier to use than trying to feed commands to the
database-provided utilities.
In any case, the reason I predeclared the $VERSION and the @...
subroutines is because I saw that in an example in some discussion of
making perl modules. Could you suggest a definitive doc for creating
modules?

Yes, there's an *awful* lot of bad Perl advice out there. A good place
to start is perldoc perlnewmod; you can ignore some of the advice that
assumes you will be uploading your module to CPAN (presumably you
won't), but from experience I would recommend packaging your modules up
into proper CPAN-style distributions. It's not hard, and the 'extra'
work you are prompted to do (writing documentation and tests) is well
worth doing anyway, and makes it much easier to install them on a new
machine, which inevitably turns out to be necessary :).
About the use Env and Env::import - my goal for these perl scripts
(programs?) was to make them executable from either the command line,
cron or some other scheduling package. So, I am indeed trying to avoid
a hash lookup, mostly for cosmetic's sake, but also for other DBA's
who have never seen perl and refuse to be brought into the [perl]
fold. It would be easier for them to see $mydir="$HOME" as opposed to
$mydir=$ENV{HOME}.

Really? I would have thought if they are unwilling to learn even that
much Perl there's little point them even trying to modify the scripts.
However, I am in the habit of calling Env qw(HOME); so as to minimize
what I'm using.

Yes, that is better.
But to be honest I really don't fully understand module coding and
"EXPORTing" and what the difference is between use Mymod and use Mymod
qw(setrun) really is. which is why I asked about a definitive doc for
that...

perldoc perlmod, and perldoc Exporter which that points you to. Note
that the code examples in perldoc Exporter, at least as of 5.8.8, do not
'use strict', which is against current best practices.

Ben

cool beans about lexical file handles vs global filehandles - I've
learned something important there. I have 'graduated' to the DBI -
much easier than the dorky sqlplus & spool "interface". I'll examine
the perlnewdoc and others closer.

thanks again,
pg
 

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

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top