Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Set env variables as part of a command

by devilock76 (Novice)
on Feb 18, 2017 at 17:13 UTC ( [id://1182274]=perlquestion: print w/replies, xml ) Need Help??

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

Ok so to real quick this I am not the most experienced perl programmer having only dug into it as needed. And well recently I needed it for something


So I have a script doing a series of system updates for a large user base. The only guarantee I have is solaris 10, unidata installed, and perl 5.10 or greater. Part of what I need to do is run some scripts against the unidata data. Withour JDBC installed for unidata it leaves me with a command line option only for getting a short data set and running a few other commands against it.


So in typical the command would look something like this

(cd $unidatadir;udt $command)


Running in a subshell is the cleanest way to do this IMO because of the cd to the directory requirement. The problem is in order to do it properly the environment variables DASP and DASU need to be set which are for an encrypted password and username respectively.


So right now my command also before the cd is setting the env variables for the subshell.

I guess what I am wondering if anyone has a perhaps cleaner way to do this as it seems slightly fragile to me for when it is distributed


Ken

Replies are listed 'Best First'.
Re: Set env variables as part of a command
by afoken (Chancellor) on Feb 18, 2017 at 17:33 UTC
    The problem is in order to do it properly the environment variables DASP and DASU need to be set which are for an encrypted password and username respectively.

    Passing passwords via environment is as insecure as via command line. But I guess that's nothing you can change. (Else, try passing the password via a file handle to an anonymous pipe.)

    For setting environment variables for a child process, try something like this:

    #!/usr/bin/perl use strict; use warnings; my $pid=fork(); defined($pid) or die "Can't fork: $!"; if ($pid) { # parent print "Parent waiting for the child ...\n"; waitpid($pid,0); print "Child has exited, exit code = $?\n"; } else { # child chdir('/tmp') or die "Can't chdir to /tmp: $!"; %ENV=(); # completely clear environment, for shorter demo output, +maybe also for security $ENV{'PATH'}='/bin:/usr/bin'; $ENV{'FOO'}='foo fofoo fofofooo'; $ENV{'BAR'}='bar bar barrrrrrrrrk'; exec($^X,'-e','print "* Hello from a new perl\n";print `pwd`;print + "* $_=$ENV{$_}\n" for sort keys %ENV; print "* bye\n"') or die "Can't execute $^X: $!"; # not reached }

    Output:

    >perl envchild.pl Parent waiting for the child ... * Hello from a new perl /tmp * BAR=bar bar barrrrrrrrrk * FOO=foo fofoo fofofooo * PATH=/bin:/usr/bin * bye Child has exited, exit code = 0 >

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
      I like that, thank you. It will have to wait till Monday till I can try it. So forking the process is that like creating a subshell or a sub perl process I am in. Sorry if I am being dense, but like I said what perl I have is rusty unfortunately.
        So forking the process is that like creating a subshell

        Excatly. That's the beauty of fork+exec, inherited from C. (Things are quite different on Windows. Perl emulates fork and exec, which makes some things quite messy.)

        fork() creates an exact clone of your currently running process, including environment, file handles and all data, except for process ID and parent process ID. (Most operating systems now use a copy-on-write mechanism, so that immediately after fork(), both process use exactly the same data. The first memory write in parent or child process transparently creates a real copy of the affected memory page. But that's an implementation detail. In the old days, fork() did a complete copy.) And yes, a successful fork() returns twice: once in the parent process, returning the process ID of the child process, and once in the child process, returning 0.

        exec() replaces the current process with another executable. Again, everything but the actual executable <UPDATE>and signal handlers</UPDATE> stays unchanged. Things like file handles, environment, and even the process ID stay the same. Command line arguments do change, to those passed to exec(). <UPDATE>Non-ignored signal handlers are reset to defaults.</UPDATE>

        Between fork() and exec(), in the (temporary) child process, you can change every aspect of the process you want: current directory, environment, file handles (for things like redirection), current user, current group.

        It's so simple that fork() does not even take arguments, and exec() just needs the name of the executable and the new command line arguments.

        Compare that with CreateProcess(), requiring no less than 10 arguments, four of them pointers to structures with 2 to 18 members, so that you effectively pass more than 30 parameters to CreateProcess(). Do you think that's sufficient? No, sorry. If you want to run a process as a different user, you need another function called CreateProcessAsUser(), taking 11 arguments. Obviously, that's still not sufficient, there are two more functions CreateProcessWithLogonW() and CreateProcessWithTokenW(). Don't ask me what happens there, I simply don't want to know that.

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
        Ok so yeah googled, learned what fork does. Let me ask another probably basic question I could not find in some googling. When I fork the program I execute I need to create an array. I need to return that array to the parent process. How would one do that?
Re: Set env variables as part of a command
by LanX (Saint) on Feb 18, 2017 at 17:58 UTC

    not sure if that's what you want, but you don't need a subshell to have temporary environment variables (at least in bash)

    lanx@lanx-1005HA:~$ echo $a,$b 0,0 lanx@lanx-1005HA:~$ a=666 b=42 perl -e 'print "@ENV{a,b}\n"' 666 42 lanx@lanx-1005HA:~$ echo $a,$b 0,0

    please note the "missing" semicolon!

    update

    and the vars don't seem to show up in the process list, though I'm no expert there

    lanx@lanx-1005HA:~$ ps -edaf |grep perl lanx 2731 2174 0 18:02 pts/2 00:00:00 perl -e print "@ENV{a, +b}\n";sleep 100

    Anyway they'll be in the bash history.

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

      and the vars don't seem to show up in the process list, though I'm no expert there lanx@lanx-1005HA:~$ ps -edaf |grep perl

      ps' command line handling is quite messy: "e" and "-e" are completely different things. "-e" shows all processes, "e" shows the environment variables.

      Environment variables are always visible, temporary or not.

      So:

      >env - foo=bar environment=unsafe sleep 100 & [1] 28318 >ps e | grep sl[e]ep 28318 pts/0 S 0:00 sleep 100 foo=bar environment=unsafe >

      Or:

      >foo=bar environment=unsafe sleep 100 & [1] 28338 >ps e | grep sl[e]ep 28338 pts/0 S 0:00 sleep 100 foo=bar environment=unsafe TERM=x +term SHELL=/bin/bash (... and many more) >

      Update: So, effectively, there are no "temporary" environment variables, at least not when looking at process environments. Shells like bash have their own set of variables, they are often referenced to as environment variables, but they aren't, at least not all of them. "Exporting" variables, e.g. with export FOO, promotes a variable from a private piece of memory to an environment variable that is passed to other processes. Prefixing a command with variable=value does the same, inside the sub-process forked to execute the command.

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1182274]
Approved by kcott
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (4)
As of 2024-04-19 06:11 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found