Pass variable from perl script to shell script in Unix - perl

Am pretty much aware of passing variables between shell scripts using 'EXPORT' command. But am stuck with passing a variable value from a perl script to shell script in UNIX operating systems.
Let me explain it clearly.
I have a parent shell called parent_shell.sh. Inside this shell script am using a variable called 'file_name' which I should fetch from child perl script.
So inside my parent_shell.sh script it will be like as follows,
perl my_perl_script.pl
file_name = 'variable' #from perl above perl script
Hope this is clear. Please let me know if it is not clear.
Thanks

Modifying the global %ENV hash in perl is equivalent to exporting variables in shell.
However, exporting variables in environment, in any language, only affects child processes, period. You can't modify parent process environment in any way.
The child script can only return anything by printing on standard output and standard error and by it's status, but that is a number 0-127 (well, it's a number 0-255, but shell can only reliably process the values up to 127).
If you just need one value from the perl script, simply print the value and use process substitution from the shell:
file_name=$(perl my_perl_script.pl)
if it is more, you can print a shell code to set the variables and use shell's eval, but make sure you quote the values correctly before printing from perl.

Related

$ENV{$variable} in perl

Is that anyway in Perl to expand the variable by in $ENV{$variable}?
I exported "a=T" and "T=b" in shell, and I run the Perl script in which print "$ENV{$a}\n", but nothing printed. I want to "b" can be printed, then how should I do in Perl?
Those environment variables should be chained you say, so
$ENV{ $ENV{a} };
Note: not $a but a, like $ENV{USER} etc. This uses the hash %ENV (see perlvar), which has the current environment, so with keys being names of environment variables.
It is apparently of interest to use a Perl variable (for the shell variable's name†) in %ENV, and not a string literal as above. In that case we need to pass that shell variable, its name or the value, to the Perl program somehow so to have it stored in a variable; can't just use it directly.
Incidentally, one of the ways to pass a variable from shell to Perl is precisely by exporting it, what then makes it available via %ENV. However, it can also be passed as usual, via command line. Assuming the use of a Perl one-liner (common in shell scripts), we have two options for how to pass
As an argument, perl -we'...' "$var", in which case it is available in #ARGV
Via the -s command switch, perl -s -we'...' -- -shv="$var", what sets up $shv variable in the one-liner, with the value $var. The -- mark the start of arguments.
See this post for details, and perhaps this one for another, more involved, example.
Note A comment asks how to pass variable's name (string a), not its value ($a). This doesn't seem as the best design to me; if the name of a variable for some reason need be passed around then it makes sense to store that in a variable (var="a") and pass that variable, as above.
But if the idea is indeed to pass the name itself around, then do that instead, so either of
perl -we'...' "a"
perl -we'...' -s -- -shv="a"
The rest is the same and %ENV uses the variable that got assigned the input.
If a full Perl script is used (not a one-liner) then use Getopt::Long to nicely handle arugments.
† A comment asks about passing the shell variable's name to a Perl variable — so a from the OP, not its value $a. I am a little uncertain of the utility of that but it is of course possible.
The two ways for how to pass a variable from shell to Perl then differ in what is passed.

How do I make a perl script run another perl script?

I am writing a large Perl script, which needs to utilize other existing Perl scripts. The problem is the main script needs to reference many different scripts from different folders. For example the main script would be contained in:
/perl/programs/io
It may need to run a script which is stored in:
/perl/programs/tools
Note that there are other orthogonal folders besides tools so I need to be able to access any of them on the fly.
Currently this is what I got:
my $mynumber = '../tools/convert.pl bin2dec 1011';
In theory it should move back from the io directory then enter the appropriate tool directory and call the convert.pl script while passing it the parameters.
All this does is store the string in the single quotes to $myNumber.
I like to assign the output of a command to an array so I can loop through the array to find error or other messages. For example if I'm making a zip file to email to someone I want to check to see if the zip program had any errors before I continue to make and send the email.
#msgs = `zip -f myfile.zip *.pl`; # Use backticks
You can also assign the output to a scalar:
$msg = `ls -al *.pl`; # Use backticks
To run any system command or script all you have to do is use `backticks`. From observing another programer's perl code, I misread these strange quotes for 'single quotes'.
backticks are also nice because they return the text in STDOUT to your perl script so that the output can be assigned to a variable, something I have found impossible if using system("");
The similar question answer does not work with my version of perl. The line
use IPC::System::Simple qw(system capture);
throws some errors. However just using system works, like this:
my $mynumber = system($^X, "../tools/convert.pl", 'bin2dec', '1011');
I can use the above without setting equal to something to execute scripts which return no value and are only sent arguments.
This seems to be the easiest way to do what I need to and the entire programs folder can be moved anywhere and it will still work as no parent directories above programs are used.

What does 'echo' do within a perl variable declaration?

I am working on transcribing an outdated file from perl to python and got caught up with some perl syntax.
my $jobID = `echo \$JOBID`;
chomp($jobID);
unless ($jobID) {
print "Please specify a job\n";
exit;
}
Thus far, I have been able to transcribe all of the command-line parsing extremely easily but am very fairly stuck here with what exactly this code is doing (specifically the echo within the declaration on line 1).
Within the perl script cmd-line parsing options - that enables one to set the jobID - it states that "default = $JOBID". So my assumption is that the first line in this code simply sets this default jobID until one is specified.
If this is the case why would you need to use echo within the variable default declaration? Is this good practice in perl or am I missing a larger picture?
I have tried searching low and high for this but can't seem to google ninja my way to anything useful.
Any help on the 'echo' would be greatly appreciated (or any good reads on this as well)!
This is one way to get a value from a shell variable. The backticks (`) run the shell command and give you the output. So the echo is running inside of a shell and in this case it just returns the one shell variable. A cleaner way to get this in Perl is to use %ENV like so:
my $jobID = $ENV{'JOBID'};
This also removes the need for chomp, avoids creating an extra process, and is much more efficient.
It is evaluating an environment variable named $JOBID and storing the result in $jobID, which (as duskwuff points out) is better accomplished using $ENV{JOBID}.
The backticks around the echo \$JOBID tell Perl to invoke the specified command in a subshell and return the output of the invoked command.

Perl backtick behaves differently than console commands

So, I'm writing a Perl script which at one point needs to process the output of another script. I tried to do this by calling the script in backticks:
my #output = `scriptName`;
I have tested the script I want to call in backticks, and it works just fine--in the same shell I'm calling my script in, even. But when I call it as part of the script, it produces no output. The variable is left empty.
I've tried executing the command with system(), but there is still no output. I have no idea why. However, the specific arguments I'm passing into the script have caused me problems before until I fixed my PATH variable. Does calling a script through a Perl script result in different environment variables somehow?
Edit: Okay, here's a potential issue. I tried using backticks and system() to print out my PATH variable, and both of them are coming up blank. Is my Perl script unable to use my PATH for some reason?
The most common cause of problems such as these, is difference in relative paths. I have a tendency of using absolute paths for that reason.
In addition, it sounds to me like your subscript might be printing to STDERR and not STDOUT. Backticks only capture STDOUT, so you need to do a redirect with the help of 2>&1
my #output = `scriptName 2>&1`;
NB: The redirect doesn't work with all shells (I believe it was tcsh that didn't support it back when i had a similar problem). Bash takes the redirect just fine.
Environment isn't your problem, unless you're explicitly adjusting it within perl, prior to calling your script. My suggestion would be - double check permissions on your script, and check relative paths. I note you don't have ./scriptName - so if it's not in your path, perl won't be able to find it either.

call the subroutine of the shell script from perl script and pass certain parameters to it

How can i call the subroutine of the shell script and pass certain parameters to it? something like below ?
#!/usr/bin/perl
### need something like this
source file.sh
routine; # <-- this is supposed to be part of file.sh which is called
# from perl script and some parameter are passed to it
No. They are two different languages. All you can do is call a shell script from Perl as a child process, using, for example, system() or qx().
Write your program in one language, Perl or shell, don't try to mix them.
OK, it is possible to export a function from a shell and then parse and execute it in Perl, but it is a lot of work, insecure, and usually not worth the effort.
A hack around this problem would be to isolate the content of routine out of file.sh into subfile.sh - then you can do this in Perl:
#cmdargs=('subfile.sh', $arg1, "arg2");
system(#cmdargs);
The first list element is the command, the second the value of a Perl variable being passed as an argument to subfile.sh; the third is a literal being passed as an argument to subfile.sh.
Avoid maintenance issues between the copy of routine's contents in subfile.sh and file.sh by writing a wrapper for subfile.sh in file.sh and simply call it with the appropriate arguments, like any other shell command, wherever you're calling routine in file.sh.
I think that would work.