setting %ENV in a module

Discussion in 'Perl Misc' started by pgodfrin, Feb 21, 2008.

  1. pgodfrin

    pgodfrin Guest

    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
    pgodfrin, Feb 21, 2008
    #1
    1. Advertising

  2. pgodfrin wrote:
    > 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>

    --
    Gunnar Hjalmarsson
    Email: http://www.gunnar.cc/cgi-bin/contact.pl
    Gunnar Hjalmarsson, Feb 21, 2008
    #2
    1. Advertising

  3. pgodfrin

    pgodfrin Guest

    On Feb 20, 7:41 pm, Gunnar Hjalmarsson <> wrote:
    > pgodfrin wrote:
    > > 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>
    >
    > --
    > Gunnar Hjalmarsson
    > Email:http://www.gunnar.cc/cgi-bin/contact.pl


    I got the same results as you - with your code. My other code is still
    screwy - more on this tomorrow...
    pg
    pgodfrin, Feb 21, 2008
    #3
  4. pgodfrin <> writes:

    > 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.

    --
    Joost Diepenmaat | blog: http://joost.zeekat.nl/ | work: http://zeekat.nl/
    Joost Diepenmaat, Feb 21, 2008
    #4
  5. pgodfrin

    pgodfrin Guest

    On Feb 21, 2:02 am, Joost Diepenmaat <> wrote:
    > pgodfrin <> writes:
    > > 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.
    >
    > --
    > Joost Diepenmaat | blog:http://joost.zeekat.nl/| work:http://zeekat.nl/


    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
    pgodfrin, Feb 21, 2008
    #5
  6. pgodfrin

    pgodfrin Guest

    ....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
    pgodfrin, Feb 21, 2008
    #6
  7. pgodfrin <> writes:

    > 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.

    --
    Joost Diepenmaat | blog: http://joost.zeekat.nl/ | work: http://zeekat.nl/
    Joost Diepenmaat, Feb 21, 2008
    #7
  8. pgodfrin <> wrote:


    > ($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
    }


    --
    Tad McClellan
    email: perl -le "print scalar reverse qq/moc.noitatibaher\100cmdat/"
    Tad J McClellan, Feb 21, 2008
    #8
  9. pgodfrin

    pgodfrin Guest

    On Feb 21, 12:50 pm, Jim Gibson <> wrote:
    > In article
    > <>,
    >
    > pgodfrin <> wrote:
    > > 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";

    >
    > > 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.

    >
    > It does, but that is not what you are doing. You are doing
    >
    > $ENV{TMPTOO} = "$TMPTOO";
    >
    > where $TMPTOO contains '$TMPTEST'.
    >
    > --
    > Jim Gibson
    >
    > Posted Via Usenet.com Premium Usenet Newsgroup Services
    > ----------------------------------------------------------
    > ** SPEED ** RETENTION ** COMPLETION ** ANONYMITY **
    > ----------------------------------------------------------
    > http://www.usenet.com


    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
    pgodfrin, Feb 22, 2008
    #9
  10. pgodfrin

    Ben Morrow Guest

    Quoth Jim Gibson <>:
    > In article
    > <>,
    > pgodfrin <> wrote:
    >
    > > 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?

    >
    > 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
    Ben Morrow, Feb 22, 2008
    #10
  11. pgodfrin

    pgodfrin Guest

    On Feb 22, 2:21 pm, Ben Morrow <> wrote:
    > Quoth Jim Gibson <>:
    >
    >
    >
    > > In article
    > > <>,
    > > pgodfrin <> wrote:

    >
    > > > 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?

    >
    > > 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


    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
    pgodfrin, Feb 23, 2008
    #11
  12. pgodfrin

    Ben Morrow Guest

    Quoth pgodfrin <>:
    >
    > 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;

    > use Env;


    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
    Ben Morrow, Feb 23, 2008
    #12
  13. pgodfrin

    pgodfrin Guest

    ....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
    pgodfrin, Feb 25, 2008
    #13
  14. pgodfrin

    Ben Morrow Guest

    Quoth pgodfrin <>:
    >
    > 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
    Ben Morrow, Feb 25, 2008
    #14
  15. pgodfrin

    pgodfrin Guest

    On Feb 24, 11:18 pm, Ben Morrow <> wrote:
    > Quoth pgodfrin <>:
    >
    >
    >
    > > 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


    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
    pgodfrin, Feb 25, 2008
    #15
  16. pgodfrin

    Ben Morrow Guest

    Quoth pgodfrin <>:
    >
    > 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
    Ben Morrow, Feb 25, 2008
    #16
  17. pgodfrin

    pgodfrin Guest

    On Feb 25, 10:46 am, Ben Morrow <> wrote:
    > Quoth pgodfrin <>:
    >
    >
    >
    > > 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
    pgodfrin, Feb 25, 2008
    #17
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. waf
    Replies:
    1
    Views:
    1,442
  2. Ankit Mehta
    Replies:
    1
    Views:
    1,426
    Simon Brooke
    Sep 29, 2006
  3. TDR
    Replies:
    3
    Views:
    174
    Daniel Berger
    Aug 31, 2007
  4. Narayanan K
    Replies:
    1
    Views:
    133
    Gabriel Horner
    Jun 18, 2010
  5. ad
    Replies:
    5
    Views:
    330
    Uri Guttman
    May 30, 2004
Loading...

Share This Page