In my perl script, i want to get the environment variable to my perl variable. I can do this
$no_of_lic = $ENV{`ON_OF_ENV`};
but this is working only for the first time if the environment variable changes in the same shell script then it will not take the updated value.
my code :
!/usr/local/bin/perl -w
$no_of_lic = $ARGV[0];
$ENV{'NO_OF_LIC'} = $no_of_lic;
print "No of lic to be picked : $no_of_lic\n";
print "Environment var : $ENV{NO_OF_LIC}\n";
sleep(1);
while ($no_of_lic != 0) {
sleep(1);
print "no of lic : $no_of_lic\n";
#$no_of_lic = $ENV{'NO_OF_LIC'};
sleep(10);
}
while the script is running in the backgorund i will change the environment variable
setenv $NO_OF_ENV 5
Once i do this, i am expecting that the script will print with updated values as 5
but its not happening .. can any one tell how to do this?
That isn't how environment variables work.
When your Perl script is launched, it gets a clone of your shell's environment. After that, while the Perl script is running, any changes to your shell's environment will not be seen in Perl's copy of the environment. (And any changes to your Perl's environment will not be seen by your shell.)
This is not specific to Perl - all scripting languages will behave the same in this regard. It's just how the environment is implemented in Unix. (And I believe Windows implements them similarly.)
If you need to send new data to a Perl script which is running in the background, investigate options such as FIFOs (a.k.a. "named pipes"), or sockets (e.g. TCP sockets). The wider term for this concept is inter-process communication (IPC), and the perlipc section of perldoc has plenty more information on the topic.
Child processes will get a copy of all variables from their parent process. Later changes of variables of the parent process will not be reflected in its child processes.
Think about it: if you change the working directory of a process and it would change the working directory of all its child processes (and in turn their children) that would be … very inconvenient (to put it mildly).
Programs are given their environment when they start. Modifying the environment in the parent (or any other process) does not update the child process' environment. If you need to communicate with the program, consider using a file (reading it each time in the loop) or some other IPC mechanism (sockets, a database, etc).
Related
I am setting env variables using *.csh file to current terminal. When I use system("/bin/tcsh *.csh") in the perl script, the *csh file executing but not setting any env variables to current terminal.
When I use system("/bin/tcsh *.csh") in the perl script, the *csh file executing but not setting any env variables to current terminal.
sub veloce_env_setup_sub {
printf "\n\n\t -veloce_env_setup option enabled\n";
system("/bin/tcsh /proj/I2BZA1/users/ssudi/SCRIPTS/veloce_env/vlab_4p4p0/veloce_setup.csh");
}
Expected: env variables should set to current terminal after sourcing *.csh file.
Actual results: only prints are comming but not setting env variables to current terminal.
perldoc -q environment:
I {changed directory, modified my environment} in a perl script. How come the change disappeared when I exited the script? How do I get my changes to be visible?
Unix
In the strictest sense, it can't be done--the script executes as a different process from the shell it was started from. Changes to a process are not reflected in its parent--only in any children created after the change. There is shell magic that may allow you to fake it by eval()ing the script's output in your shell; check out the comp.unix.questions FAQ for details.
In your code the problem appears twice:
system spawns tcsh, which runs a script that sets environment variables. These environment variables only exist within the tcsh process. When system returns (i.e. when tcsh exits), the environment of the child process is gone.
Even if you managed to modify the environment of the perl script (which you can do by assigning to %ENV), that wouldn't affect the parent shell that perl was started from.
This can now be done with Env::Modify.
use Env::Modify qw(:tcsh source);
sub veloce_env_setup_sub {
printf "\n\n\t -veloce_env_setup option enabled\n";
source("/proj/I2BZA1/users/ssudi/SCRIPTS/veloce_env/vlab_4p4p0/veloce_setup.csh");
}
The environment of a child process doesn't affect the environment of the parent process. That is, a process that you start doesn't change the environment of the thing that started it.
If you want to set up the environment for a Perl script, you have some options. Which one works best for you depends on what you are trying to do.
Set up the options inside Perl. Instead of using a shell program, do it all in Perl by setting values in the %ENV hash. This works well if you just need it for that program. It's likely that whatever you are doing in tcsh you can do it Perl.
Instead of calling the shell script from Perl, call your Perl program from the shell script. Now the shell script is the parent process and the child process (the Perl program) inherits the parent's environment.
#!tcsh
setenv SOME_VALUE foo
perl my_program
In a child process, you could print the environment and read that from the parent process. You'd parse it and convert it appropriately. This is what the Env::Modify module does, but I wouldn't want that as my first option.
You can't access environment variables in a process that have been set by a child process. It's a fundamental property of how processes work.
You can set %ENV{'your_choice'} = 'as you like'; inside Perl.
Sure, it looks like a little bit hartverdrahtet (yt), but it works great again. So the environmental is mental just inner the mind of top instanced script and closed and removed on closing it.
Another way is calling system("set VARIABLE=VALUE");
Here the variable lefts after closing until next reboot.
I have tried this code but it doesnt work for the user-input directory.
It only lists the PWD.
Help!
#script to list the directory contents of a user specified directory
system("pwd");
print "enter the path of your d1rectory\n";
$path =<STDIN>;
system(" cd Spath");
#system ("chdir $path");
system("ls");
A Unix process has something called an "environment" associated with it. The environment contains details of how the process is being run. One of the elements of the environment, for example, is the current working directory.
When a process starts another process, the new, child process inherits a copy of the environment from the parent process. The child process can change anything it wants in its copy of the environment, but it cannot change the parent's copy of the environment (or, at least, not easily).
Your code involves four processes. In call to system() creates a new process, with a new copy of the environment. When each call to system() exits, its environment ceases to exist.
Your program is the first process. It inherits a copy of the environment of the shell process that starts it. This environment has a current working directory.
The first call to system() creates a new process and gives it a copy of the main program's environment. That subprocess runs pwd and exits. Its copy of the environment disappears.
The next call to system() creates another new process and gives it a new copy of the main program's environment. That subprocess changes its current working directory - but only for its copy of the environment. When the call to system() exits, that copy of the environment (with its changed current working directory) ceases to exist).
The final call to system() creates another new process and gives it a new copy of the main program's environment (which still has the original program's current working directory). That process calls ls on its current directory and then exits - removing its environment in the process.
So, effectively, your call to cd does nothing as it changes the directory in an environment that immediately ceases to exist.
The quick fix (as you have been shown) is to just pass the $path variable to ls.
The correct fix (as you have also been shown) is to not use subprocesses to do this and to use, instead, Perl's built-in tools.
When I see questions like this, I have to wonder what they are teaching on computing courses these days :-)
Already #toolic mentioned in a comment you have to make system "ls $path"
But you are already in Perl, you can use you the Perl Inbuilt functions like glob or opendir. for example
my $s = <STDIN>;
chomp $s;
$s .= '/' if length($s);
while(my $file = glob("\Q$s\E*")){
print $file,"\n";
}
I need to source configuration file 'eg.conf' to terminal though perl script. I am using system command but its not working.
system('. /etc/eg.conf')
Basically I am writing script in which later point it will use the environment variable (under conf file) for execute other process.
It is not clear what you are trying to achieve, but if you want to make the config available from within Perl AND your config file is valid Perl code you can use do or require (see perldoc for more information).
What you are doing in your code is to spawn a shell with system, include the config inside this shell (which must be in shell syntax) and then exit the shell again which of course throws all the config away on close. I guess this is not what you intend to do, but your real intention is not clear.
What is your goal? Do you need to source eg.conf to set up further calculations from within a perl controlled shell, or are you trying to affect the parent shell that is running the perl script?
Your example call to system('. /etc/eg.conf') creates a new shell subprocess. /etc/eg.conf is sourced into that shell at which point the shell exits. Nothing is changed within the perl script nor in the parent process that spawned the perl script.
One can not modify the environment of a parent process from a child process, without the assistance of the parent process[1]. One generally returns code for the parent shell to source or to eval.
1: ok, one could theoretically affect the parent process by directly poking into its memory space. Don't do that.
I have this command that I load (example.sh) works well in the unix command line.
However, if I execute it in Perl using the system or ` syntax, it doesn't work.
I am guessing certain settings like environment variables and other external sh files weren't loaded.
Is there an example coding to ensure it will work?
More Updates on coding execution failure (I have been trying with different codes):
push (#JOBSTORUN, "cd $a/$b/$c/$d; loadproject cats; sleep 60;");
...
my $pm = new Parallel::ForkManager(3);
foreach my $job (#JOBSTORUN) {
$pm->start and next;
print(`$job`);
$pm->finish;
}
print "\n\n[DONE] FINISHED EXECUTING JOBS\n";
Output Messages:
sh: loadproject: command not found
Can you show us what you have tried so far? How are you running this program?
My first suspicion wouldn't be the environment if you are running it from a login shell. any Perl script you start (well, any program, really) inherits the same environment. However, if you are running the program through cron, then that's a different story.
The other mistakes I usually make in these situations is specifying the relative paths incorrectly. The paths are fine from the command line, but my Perl script has some other current working directory.
For general advice, see Interact with the system when Perl isn't enough. There's also a chapter in Learning Perl about this.
That's about the best advice you can hope for given the very limited information you've shared with us.
On a Solaris box in a "mysterious production system" I'm running a Perl script that references an environment variable. No big deal.
The contents of that variable from the shell both pre- and post-execution are what I expect.
However, when reported by the script, it appears as though it's running in some other sub-shell which is clobbering my vars with different values for the duration of the script.
Unfortunately I really can't paste the code. I'm trying to get an atomic case, but I'm at my wit's end here.
Is it possible that your script or any libraries that you are 'use'-ing mess around with the %ENV hash?
Can you run the code through the Perl debugger to see where it's going? Can you dump the pid ($$) to check if it is forking or invoking subshells?
Alternatively, you could sprinkle print statements throughout the code to narrow down at what point the environment variable is being altered, or start stubbing out components that are not likely to be relevant to hone in on the trouble spot.
1) What version of Perl?
2) Some environment variables can be clobbered by child processes, I believe. Can you do a ps?
Ok, here's what was going on:
perl itself was a red herring entirely.
The script was executing in a child shell which, when created, was re-loading rc files. Those rc files were blowing away the environment variables I had manually added during the parent shell with reference copies.
I was able to demonstrate this with a simple csh script that just echoed just echoed the environment.
De-wonkifying my rc files (which were overwrought with wonkitude) cleared up the mystical replacement.
UPDATE: The test that proved this was a "test.sh" that had a simple "set" command. It proved that the sub-shell wasn't inheriting the parent environment correctly. Oddly, when I switched my parent interactive shell to ksh, the environment began inheriting correctly.