Output of bash script in perl script - perl

I want to embed a bash script inside a perl script. I want to run my bash script by taking some variables from the perl script. Once it gets the variable the bash script takes over and tries to output the files that is created within.
How can I pass the perl script variable to my bash script ?
I do not know perl but from what I read in Google, I can embed my bash script as
system("get_files.cmd -yr ${year}");
where my bash script is get_files.cmd.

I think it might be better if you passed them as arguments to your bash script.
The perl call:
system("get_files.cmd ${var1} ${var2}");
The bash script
var1="$1"
var2="$2"
...
Where $1, $2 are the arguments passed in the command line (in order). Note that you can use the $# bash variable to get the number of arguments passed.
Hope this helps =)

The Expect module can essentially automate shell tasks such as running scripts and passing perl variables. Such that:
Use Expect;
# create an Expect object by spawning another process
my $exp = Expect->spawn($command, #params)
or die "Cannot spawn $command: $!\n";
http://search.cpan.org/~rgiersig/Expect-1.15/Expect.pod

Related

wrapper script and GetOpts::Long perl

I have been trying to make GetOpts :: Long work for my code but it just doesn't respond. I have a wrapper script with about 8 scripts and 2 commands. I have been trying to GetOpts :: Long submit arguments into the separate codes, but it doesnt work!
For example, I've script 1 though 8, and on the command line I'm trying to a few options that I would like to submit to the separate scripts. When I use the GetOpts module in the seprate scripts and run them separately, they run fine. But when I try to run the wrapper script, say wrapper.pl which initiates script 1 with the module being called in it; the arguments submitted are not being taken by the separate scripts.
Please help!!!!
I hope this sort of explains the problem. wrapper script looks like this(wrapper.pl),using backticks:
perl script1.pl;
perl script2.pl; (etc)
script1.pl uses the GetOpts::Long option for the input file. script1.pl calls for the input file using the "-i" option, but the file is not being read when initiated on the command line.
command line option: perl wrapper.pl -i seqs.fa -o op.fa
Do you actually pass in the arguments from your wrapper.pl into the
scripts ? - how would they magically know what options they need to
handle?
vanHoesel asked the right questions; you have to do something like that in wrapper.pl:
use Getopt::Long;
GetOptions('i=s' => \$input_file,
'o=s' => \$output_file) || die "Usage: $0 -i INPUT -o OUTPUT\n";
`perl script1.pl -i $input_file`;
`perl script2.pl -o $output_file`;

Shell calling perl and returning back string to Shell Script

I have a shell script , i want to call a perl script to do some compute, once perl is called i want perl to process it and while returning i want it to return not exit code but a string back to shell script ? how can i do that?
Here is my simple piece of code calling perl in shell script
VAR=$(perl Test.pl)
Quick and dirty would be to have the perl script print the Information to STDOUT and just call it in your Shell script by backticks or just as you did.
Along the lines of
VAR=`perl Test.pl`
This will put everything the perl script printed to STDOUT into VAR.

Executing perl code inside shell script using eval

I came across the following example. I tried to google but could not find much so I'm posting this question here.
What is the benefit of executing the perl script like this?
How can we make the shell script work like a "normal" shell script once we are through executing the perl code?
Here's the code:
#!/bin/ksh
#! -*- perl -*-
eval 'exec $PERLLOCATION/bin/perl -x $0 ${1+"$#"} ;'
if 0;
print "hello world\n";
# how can I make it behave like a "normal" shell script from this point onwards? What needs to be done?
# echo "hello world" ### this results in error
This idiom is described in the perlrun documentation.
The -x switch scans the whole file and ignores anything that appears before the first line that begins with #! and also contains the word perl.
It means that your system will run the script with the Perl interpreter whether you invoke the script with perl or with a shell command (sh/bash/ksh/etc.)
That is,
$ perl this_script
and
$ sh this_script
will both run the script with perl.
To address your second question, this idiom has just about nothing to do with combining shell script and Perl script in the same file. There are a few different ways to approach that problem, but maybe the most readable way is to write in shell script, but use the shell's heredoc notation to invoke perl code.
#!/bin/bash
# this is a bash script, but there is some Perl in here too
echo this line is printed from the shell
echo now let\'s run some Perl
perl <<EOF
# this is now perl script until we get to the EOF
print "This line is printed from Perl\n";
EOF
echo now this is from the shell script again
1. If you start a Perl script in the usual way:
#!/usr/bin/perl
print "hello world\n";
the #! line will only work if the Perl interpreter is actually installed under /usr/bin. The perl/ksh bilingual script you show is a tricky kluge to make the script work even if perl is installed somewhere else. For more information, see e.g. this.
2. You can't. When the shell process encounters the exec command, it terminates and hands control over to perl. (Technically, it executes perl in place of the shell, without creating a new process.) The only way to run more shell commands after that would be to launch a new shell.
It's way simpler than what's already been posted.
#!$PERLLOCATION/bin/perl
doesn't work because the shebang (#!) line is interpreted by the kernel (not the shell), and the kernel doesn't do variable interpolation.
The code invokes ksh to expand the environment variable and to launch the specified installation of Perl.

Have perl execute shellscript & take over env vars

I have a shell script that does nothing but set a bunch of environment variables:
export MYROOTDIR=/home/myuser/mytools
export PATH=$MYROOTDIR/bin:$PATH
export MYVERSION=0.4a
I have a perl script, and I want the perl script to somehow get the perl script to operate with the env vars listed in the shell script. I need this to happen from within the perl script though, I do not want the caller of the perlscript to have to manually source the shellscript first.
When trying to run
system("sh myshell.sh")
the env vars do not "propagate up" to the process running the perl script.
Is there a way to do this?
To answer this question properly, I need to know a bit more.
Is it okay to actually run the shell script from within the perl script?
Are the variable assignments all of the form export VAR=value (i.e. with fixed assignments, no variable substitutions or command substitutions)?
Does the shell script do anything else but assign variables?
Depending on answers to these, options of different complexity exist.
Thanks for the clarification. Okay, here's how to do it. Other than assigning variables, your script has no side effects. This allows to run the script from within perl. How do we know what variables are exported in the script? We could try to parse the shell script, but that's not the Unix way of using tools that do one thing well and chain them together. Instead we use the shell's export -p command to have it announce all exported variables and their values. In order to find only the variables actually set by the script, and not all the other noise, the script is started with a clean environment using env -i, another underestimated POSIX gem.
Putting it all together:
#!/usr/bin/env perl
use strict;
use warnings;
my #cmd = (
"env", "-i", "PATH=$ENV{PATH}", "sh", "-c", ". ./myshell.sh; export -p"
);
open (my $SCRIPT, '-|', #cmd) or die;
while (<$SCRIPT>) {
next unless /^export ([^=]*)=(.*)/;
print "\$ENV{$1} = '$2'\n";
$ENV{$1} = $2;
}
close $SCRIPT;
Notes:
You need to pass to env -i all environment your myshell.sh needs, e.g. PATH.
Shells will usually export the PWD variable; if you don't want this in your perl ENV hash, add next if $1 eq 'PWD'; after the first next.
This should do the trick. Let me know if it works.
See also:
http://pubs.opengroup.org/onlinepubs/009695399/utilities/export.html
http://pubs.opengroup.org/onlinepubs/009695399/utilities/env.html
Try Shell::Source.
You can set the environment variables inside the BEGIN block.
BEGIN block is executed before the rest of the code, setting the environment variables in this block makes them visible to the rest of the code before it is compiled and run.
If you have any perl modules to 'use' based on the enviornment settings, BEGIN block makes it possible.
Perl uses a special hash %ENV to maintain the environment variables.
You can modify the contents of this hash to set the env variables.
EXAMPLE :
BEGIN
{
$ENV { 'MYROOTDIR' } = '/home/myuser/mytools';
$ENV { 'PATH' } = "$ENV{ 'MYROOTDIR' }/bin:$ENV{ 'PATH' }";
}
Wouldn't it be easier for a shell script to set the variables, and then call the perl program?
i.e.:
run.sh:
#!/bin/sh
export MYROOTDIR=/home/myuser/mytools
export PATH=$MYROOTDIR/bin:$PATH
export MYVERSION=0.4a
./program.pl
This can now be done with Env::Modify with few changes to your existing code.
use Env::Modify 'system';
...
system("sh myshell.sh");
print $ENV{MYROOTDIR}; # "/home/myuser/mytools"
or if all your shell script does is modify the environment, you can use the source function
use Env::Modify `source`;
source("myshell.sh");
print $ENV{MYVERSION}; # "0.4a"

How can I call a Perl function from a shell script?

I have written a library in Perl that contains a certain function, that returns information about a server as a character string. Can I call this function from a shell directly?
My boss asks "Can you call it from a shell directly for the time being?" Because he said that, I think I should be able to do it, but how do I do it?
perl -MServerlib=server_information -e 'print server_information()'
Is another way to do this, but only if Serverlib exports server_information sub. If it doesn't, you would need to do the below instead:
perl -MServerlib -e 'print MServerlib::server_information()'
As perl's command line arguments are a bit inscrutable, I'd wrap it in a simpler perl script that calls the function. For example, create a script serverinfo which contains:
#!/usr/bin/perl
require 'library.pl';
say library::getServerInformation();
then run:
chmod u+x serverinfo
The advantage of doing it this way is the output and arguments of the script can be corrected if the function itself changes. A command line script like this can be thought of as an API, which shouldn't change when the implementation changes.