Perl: Calling a perl script from another - perl

I have a perl script which calls another script. I am calling it using backticks and passing argument to that script and it works fine.
`CQPerl call_script.pl $agr1 $agr2 $arg3`;
But please suggest if there is another better way to do so. How can I check if the script errored out because of the calling script or the script that was called. How do I do that check from the calling script itself?

If you wan't to do error checking, backticks may be a wrong approach. You probably want to use the system function. See the documentation for all the details of error handling, examples included.
Perl has a number of possibilites to execute other scripts / commands:
backticks / qx{} When you want to read all the output at once after the program has terminated
exec When you wan't to continue your process as another program — never returns if succesfull
system When you are only interested in the success or failure of the command
open When you want to pipe information to or from the command
do and require Execute another Perl script here. Similar to C's #include
There are modules to do a three-way open so that you have access to STDIN, STDOUT and STDERR of the program you executed. See the apropriate parts of perlipc for advanced information.
And always use the multi-argument forms of these calls to avoid shell escaping (can be annoying and very insecure).

Check the value of the perl special variable $? to determine if there was an error.

Related

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.

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.

How to debug a perl script used inside another perlscript?

How to debug a perl script used inside another perlscript. We can debug both separately. Is it possible to debug in one step?
Ex:
!/user/bin/perl
my $param= 8;
my #res=\`perl extract.pl $config`;
print "The results is .... #res\n";
Similarly, can we debug the perl scripts used inside shell script?
Thanks.
You can add -d switch to the shebang line of the script you are invoking:
#!/usr/bin/perl -d
A dynamic solution:
my $dswitch = $INC{"perl5db.pl"} ? "-d" : "";
my #res=`perl $dswitch extract.pl $config`;
$INC{"perl5db.pl"} is true when you are using the debugger, and false when you are not.
The "correct" thing to do would be to change your design so you are not calling the other script through a system command. Then you would have a single debugging environment.
The best design would be to make extract.pl into a module.
You could also use the do command to import the code from the other file: do 'extract.pl'. Then the only change needed would probably be the way you pass $config in.
Either of these approaches would be quite simple to implement and would have other benefits for continued development. Maybe you have a good reason not to do it this way, but I would consider this first if you haven't already.
Just debug extract.pl passing in the value in $config. If you don't know what it is, the age-old printf will do that for you.
say "\$config='$config'";
And then do:
perl -d extract.pl 'Stuff that printed in config'.
As the two are isolated processes, the only communication is what is passed on the command line and what is printed by the called script. So the called script should be capable of being tested without the calling script. (Unless you've set up some sort of IPC or shared memory or something tricky like that.)

What's the differences between system and backticks and pipes in Perl?

Perl supports three ways (that I know of) of running external programs:
system:
system PROGRAM LIST
as in:
system "abc";
backticks as in:
`abc`;
running it through a pipe as in:
open ABC, "abc|";
What are the differences between them? Here's what I know:
You can use backticks and pipes to get the output of the command easily.
that's it (more in future edits?)
system(): runs command and returns command's exit status
backticks: runs command and returns the command's output
pipes : runs command and allows you to use them as an handle
Also backticks redirects the executed program's STDOUT to a variable, and system sends it to your main program's STDOUT.
The perlipc documentation explains the various ways that you can interact with other processes from Perl, and perlfunc's open documentation explains the piped filehandles.
The system sends its output to standard output (and error)
The backticks captures the standard output and returns it (but not standard error)
The piped open allows you to capture the output and read it from a file handle, or to print to a file handle and use that as the input for the external command.
There are also modules that handle these details with the cross-platform edge cases.
system is also returning the exit value of the application (ERRORLEVEL in Windows).
Pipes are a bit more complicated to use, as reading from them and closing them adds extra code.
Finally, they have different implementation which was meant to do different things. Using pipes you're able to communicate back with the executed applications, while the other commands doesn't allow that (easily).
Getting the program's exit status is not limited to system(). When you call close(PIPE), it returns the exit status, and you can get the latest exit status for all 3 methods from $?.
Please also note that
readpipe('...')
is the same as
`...`