trschau has asked for the wisdom of the Perl Monks concerning the following question:

In most unix shells, there is a concept of sourcing or dotting as it may be also called. My understanding of this concept is that the current process reads a file without having to start a sub process, thus, variables that are set within the script which is read, may stay resident in the current shell. Since a perl program is aways executed a sub process is started. Environmentals that are set via a system call or via the ENV command are not passed up to the calling process (basic UNIX). Is their a method where perl can mimic SHELL sourcing? Thank you.

Replies are listed 'Best First'.
Re: sourcing
by MZSanford (Curate) on Aug 23, 2001 at 20:48 UTC
    It's not nice, or good, but i did the following :
    #!/usr/bin/perl $ENV{WATSON} = "It Worked"; print "Shelling ...\n"; exec('ksh');
    and with a run saw ...
    %shell >./shellme.pl Shelling ... %shell >echo $WATSON It Worked %shell >
    But, this is not remotly safe ... it clobered certain shell optinos, not to mention this version forces ksh. I do not suggest this unless there is absolutly no other way. (and if so, please check $ENV{SHELL}, but be sure to also include a default)
    can't sleep clowns will eat me
    -- MZSanford
Re: sourcing
by VSarkiss (Monsignor) on Aug 23, 2001 at 20:52 UTC

    I can interpret your question two different ways.

    If you mean, "Can a Perl program in one file read and execute a Perl program in another file without creating another process", the answer is yes. You could read the file into a scalar variable, and eval it. The "read-ee" program would have access to the variables in the "read-er" program (discovering whether that's a good idea or not is an exercise for the reader ;-)

    If you mean, "Can a shell program execute a Perl program in such a way that the Perl program can change variables in the Shell program", the answer is no. A shell can't "source" a Perl program. Unless you had a Perl shell, of course....

    HTH

Re: sourcing
by maverick (Curate) on Aug 23, 2001 at 20:57 UTC
    I *think* I know what you're after. You want something like:
    slurp "my_other_stuff";
    and then all the other stuff, variables, functions etc are directly accessable inside you program. right? Well, there isn't anything directly like that, and further, most would counsider something like that bad(tm). But, here is what perl does have.

    First I'd suggest reading perldoc perlmod and perldoc perlboot to get an idea of how packages and objects work in perl. I'll throw a quick example at you to get you rolling.

    # here is my file of common stuff package my_stuff; # this tells perl how to name this collection of thi +ngs sub my_function { # stuff } 1; # this let's perl know that the package has loaded ok.
    Now in your other program(s) you can say:
    #!/usr/bin/perl use my_stuff; # this will look for a package named "my_stuff.pm" in +the directories listed in @INC my_stuff::my_function($arg1,$arg2);
    You have to tell perl which package to find my_function in, thus the 'my_stuff::' part. There is a way to get variables too, but it's considered bad design. :)

    This is a *very* simplified example, but I hope this helps.

    /\/\averick
    perl -l -e "eval pack('h*','072796e6470272f2c5f2c5166756279636b672');"

Re: sourcing
by Masem (Monsignor) on Aug 23, 2001 at 20:53 UTC
Re: sourcing
by kjherron (Pilgrim) on Aug 23, 2001 at 21:33 UTC
    If you want the perl script to modify the parent shell's environment, there is a way, but the two processes have to cooperate.

    The basic idea is that the subprocess--the perl script--should print shell commands to its stdout, which the parent process--the shell--would capture and execute. For instance, here's a trival script to set your terminal type:

    #!/usr/local/bin/perl print "TERM=", $ARGV[0], " export TERM\n";
    Run it like this:
    eval `myterm vt100`
    and your shell will dutifully set its TERM variable to vt100 (assuming you're using a bourne-like shell).

    The subprocess may need to look at the SHELL environment variable so that it can produce sh or csh style output as appropriate. And the user wanting to use this command may want to set up an alias or shell function to make the command easier to type.

    The unix "resize" command uses this technique. You should take a look at its man page.

Re: sourcing
by BastardOperator (Monk) on Aug 23, 2001 at 22:03 UTC
    I'm guessing that you want this
    require "dotsh.pl"; $ENV{SHELL} = "/bin/sh"; dotsh("/path/to/some/sourcable/file");
    Update: looking back, I think I misunderstood your question, but I'll leave this here anyways.

    :|BastardOperator|:
          {From Hell}
Re: sourcing
by dga (Hermit) on Aug 24, 2001 at 02:31 UTC

    You may be wanting something like this.

    do "myfile";

    That will read in the specified file as perl and execute it in place right then.

    The camel says its like doing a require with an eval, but more efficient and gives file and line for errors. It will re read and reparse the entire file for each call so it is not that good in loops unless the file changes with each pass of the loop.

      We just ran into a snag with this though. It doesn't work right (or at least we haven't been able to make it work right) with the use of strict. Any ideas on that?

      Update
      The way we fixed it was by explicitly making the sourced file a package:

      { package PACKAGE_NAME;do "sourced_file.pl" };

      and then we had to explicitly call each symbol by its package name in order to reference the data "inside" the symbol.

      print $PACKAGE_NAME::variable,"\n";

      Any other way we tried wouldn't work right *shrug*.

      _ _ _ _ _ _ _ _ _ _
      - Jim
      Insert clever comment here...