How to run a perl script from another passing parameters? - perl

How to run a perl script from another passing parameters?
I'm trying to use a solution found in a internet post that i can't find anymore.
It was something like:
do 'script.cgi param1 param2';
And in the other script I'm using simply the shift to get those parameters:
#Parameters
my $param1= shift;
my $param2= shift;
I saw people using system with args, but is it better for real?
If not, how can I fix the solution with 'do EXPR'?
Thanks in advance.

Oh well, I solved doing:
{local #ARGV = (#my_args); do $script;}
It works. If anybody has any better suggestions feel free to tell them to me.
Meantime i'm using this solution.

Actually, there are two better ways I can think of:
system($script, #my_args);
and
my $cmd = $script . ' ' . join(' ', #my_args);
my $return = `$cmd`;
Both solutions pass the arguments in #my_args. The system() call returns the exit code of the executed program, while the backticks solution (``) returns the output for later parsing.

Related

`ssh host command` can't return the result of the command

There are several computers , I want to use who command to see who is online . I write a script can let me check all the computers but it seems don't return the information of who is online ....
The computer just pause .
I try type this command => ssh f-001 who , and it works . But when I write it to the script , it fails .
here is my code
#Hosts = ("f-001","f-002","f-003","f-004","f-005");
for($i=0;$i<=$#Hosts;$i++)
{
`ssh $Hosts[$i] who`;
getc();
}
thanks
~
~
The results aren't displayed because while you're executing the command, you're not actually displaying its output; you'd need to do something like
print `ssh $Hosts[$i] who`;
Assuming you're using ssh-agent, Kerberos, or something else that lets you login without giving a password, the pause is just the `getc().
Use system() instead:
#Hosts = ("f-001","f-002","f-003","f-004","f-005");
foreach $host (#Hosts)
{
system ("ssh $host who");
}
And please do not iterate with $i.
Run3 is even more convenient.
I would like to add one thing over here is that if you want to do further processiong with the data coming out from the command then remember you need to capture the output like
my #users = `ssh $Hosts[$i] who`;
I think the answers here cover what you need but would emphasize the value of using foreach e.g.:
foreach my $host ("mail1", "san", "ws100.internal"){ say qx/ping -c1 $host/}
How do you plan to deal with the output? Unless you are watching the terminal you're going to want to log or write the results somewhere. Log::Dispatch is pretty simple but you can make your script log to files, rotate them, send email etc.
If you are going to do a lots of remote execution and monitoring be sure to take a look at Rex https://metacpan.org/pod/Rex (and http://www.rexify.com).

Call one URL from Perl script

I have one Perl script which contains some code to call one URL. URL pointing to a servlet for storing some data in the data base, based on the parameter passing through the url.I was working with the code below but failed to call the url and fail to store the data in the data base.
#!/appl/teamsite/iw-perl/bin/iwperl
for (#ARGV) { printf "%d %s\n", $i++, $_};
my $environment=$ARGV[0];
my $jobid = $ARGV[1];
my $taskID = $ARGV[2];
my $workArea= $ARGV[3];
my $jobDocument = $ARGV[4];
my $url = "http://localhost:7001/JCreationServlet?command=build"."&environment=".$ARGV[0]."&jobID=".$ARGV[1]."&taskID=".$ARGV[2]."&workArea=".$ARGV[3]."&jobDocument=".$ARGV[4];
print "Url is $url\n";
'wget '.$url;
Please help me so that I can able to call the URL.
'wget '.$url;
should be backticks, if you want it to be executed
`wget $url`
In your code:
'wget '.$url;
is simply a string.
Please refer this to execute the external commands.
You could use `wget $url`, instead of what you have and this would fix it. However, I recommend using the system call, as it is better practice:
system("wget",$url);
However, if you for some reason need the output, then it would be best to use the backticks and capture it like this:
my $response = `wget $url`;

Can I obtain values from a perl script using a system call from the middle of another perl script?

I'm trying to modify a script that someone else has written and I wanted to keep my script separate from his.
The script I wrote ends with a print line that outputs all relevant data separated by spaces.
Ex: print "$sap $stuff $more_stuff";
I want to use this data in the middle of another perl script and I'm not sure if it's possible using a system call to the script I wrote.
Ex: system("./sap_calc.pl $id"); #obtain printed data from sap_calc.pl here
Can this be done? If not, how should I go about this?
Somewhat related, but not using system():
How can I get one Perl script to see variables in another Perl script?
How can I pass arguments from one Perl script to another?
You're looking for the "backtick operator."
Have a look at perlop, Section "Quote-like operators".
Generally, capturing a program's output goes like this:
my $output = `/bin/cmd ...`;
Mind that the backtick operator captures STDOUT only. So in order to capture everything (STDERR, too) the commands needs to be appended with the usual shell redirection "2>&1".
If you want to use the data printed to stdout from the other script, you'd need to use backticks or qx().
system will only return the return value of the shell command, not the actual output.
Although the proper way to do this would be to import the actual code into your other script, by building a module, or simply by using do.
As a general rule, it is better to use all perl solutions, than relying on system/shell as a way of "simplifying".
myfile.pl:
sub foo {
print "Foo";
}
1;
main.pl:
do 'myfile.pl';
foo();
perldoc perlipc
Backquotes, like in shell, will yield the standard output of the command as a string (or array, depending on context). They can more clearly be written as the quote-like qx operator.
#lines = `./sap_calc.pl $id`;
#lines = qx(./sap_calc.pl $id);
$all = `./sap_calc.pl $id`;
$all = qx(./sap_calc.pl $id);
open can also be used for streaming instead of reading into memory all at once (as qx does). This can also bypass the shell, which avoids all sorts of quoting issues.
open my $fh, '-|', './sap_calc.pl', $id;
while (readline $fh) {
print "read line: $_";
}

What Perl module can I use to test CGI output for common errors?

Is there a Perl module which can test the CGI output of another program? E.g. I have a program
x.cgi
(this program is not in Perl) and I want to run it from program
test_x_cgi.pl
So, e.g. test_x_cgi.pl is something like
#!perl
use IPC::Run3
run3 (("x.cgi"), ...)
So in test_x_cgi.pl I want to automatically check that the output of x.cgi doesn't do stupid things like, e.g. print messages before the HTTP header is fully outputted. In other words, I want to have a kind of "browser" in Perl which processes the output. Before I try to create such a thing myself, is there any module on CPAN which does this?
Please note that x.cgi here is not a Perl script; I am trying to write a test framework for it in Perl. So, specifically, I want to test a string of output for ill-formedness.
Edit: Thanks
I have already written a module which does what I want, so feel free to answer this question for the benefit of other people, but any further answers are academic as far as I'm concerned.
There's CGI::Test, which looks like what you're looking for. It specifically mentions the ability to test non-Perl CGI programs. It hasn't been updated for a while, but neither has the CGI spec.
There is Test::HTTP. I have not used it, but seems to have an interface that fits your requirements.
$test->header_is($header_name, $value [, $description]);
Compares the response header
$header_name with the value $value
using Test::Builder-is>.
$test->header_like($header_name, $regex, [, $description]);
Compares the response header
$header_name with the regex $regex
using Test::Builder-like>.
Look at the examples from chapter 16 from the perl cookbook
16.9. Controlling the Input, Output, and Error of Another Program
It uses IPC::Open3.
Fom perl cookbook, might be modified by me, see below.
Example 16.2
cmd3sel - control all three of kids in, out, and error.
use IPC::Open3;
use IO::Select;
$cmd = "grep vt33 /none/such - /etc/termcap";
my $pid = open3(*CMD_IN, *CMD_OUT, *CMD_ERR, $cmd);
$SIG{CHLD} = sub {
print "REAPER: status $? on $pid\n" if waitpid($pid, 0) > 0
};
#print CMD_IN "test test 1 2 3 \n";
close(CMD_IN);
my $selector = IO::Select->new();
$selector->add(*CMD_ERR, *CMD_OUT);
while (my #ready = $selector->can_read) {
foreach my $fh (#ready) {
if (fileno($fh) == fileno(CMD_ERR)) {print "STDERR: ", scalar <CMD_ERR>}
else {print "STDOUT: ", scalar <CMD_OUT>}
$selector->remove($fh) if eof($fh);
}
}
close(CMD_OUT);
close(CMD_ERR);
If you want to check that the output of x.cgi is properly formatted HTML/XHTML/XML/etc, why not run it through the W3 Validator?
You can download the source and find some way to call it from your Perl test script. Or, you might able to leverage this Perl interface to calling the W3 Validator on the web.
If you want to write a testing framework, I'd suggest taking a look at Test::More from CPAN as a good starting point. It's powerful but fairly easy to use and is definitely going to be better than cobbling something together as a one-off.

How can I capture the stdin and stdout of system command from a Perl script?

In the middle of a Perl script, there is a system command I want to execute. I have a string that contains the data that needs to be fed into stdin (the command only accepts input from stdin), and I need to capture the output written to stdout. I've looked at the various methods of executing system commands in Perl, and the open function seems to be what I need, except that it looks like I can only capture stdin or stdout, not both.
At the moment, it seems like my best solution is to use open, redirect stdout into a temporary file, and read from the file after the command finishes. Is there a better solution?
IPC::Open2/3 are fine, but I've found that usually all I really need is IPC::Run3, which handles the simple cases really well with minimal complexity:
use IPC::Run3; # Exports run3() by default
run3( \#cmd, \$in, \$out, \$err );
The documentation compares IPC::Run3 to other alternatives. It's worth a read even if you don't decide to use it.
The perlipc documentation covers many ways that you can do this, including IPC::Open2 and IPC::Open3.
Somewhere at the top of your script, include the line
use IPC::Open2;
That will include the necessary module, usually installed with most Perl distributions by default. (If you don't have it, you could install it using CPAN.) Then, instead of open, call:
$pid = open2($cmd_out, $cmd_in, 'some cmd and args');
You can send data to your command by sending it to $cmd_in and then read your command's output by reading from $cmd_out.
If you also want to be able to read the command's stderr stream, you can use the IPC::Open3 module instead.
IPC::Open3 would probably do what you want. It can capture STDERR and STDOUT.
http://metacpan.org/pod/IPC::Open3
A very easy way to do this that I recently found is the IPC::Filter module. It lets you do the job extremely intuitively:
$output = filter $input, 'somecmd', '--with', 'various=args', '--etc';
Note how it invokes your command without going through the shell if you pass it a list. It also does a reasonable job of handling errors for common utilities. (On failure, it dies, using the text from STDERR as its error message; on success, STDERR is just discarded.)
Of course, it’s not suitable for huge amounts of data since it provides no way of doing any streaming processing; also, the error handling might not be granular enough for your needs. But it makes the many simple cases really really simple.
I think you want to take a look at IPC::Open2
There is a special perl command for it
open2()
More info can be found on: http://sunsite.ualberta.ca/Documentation/Misc/perl-5.6.1/lib/IPC/Open2.html
If you do not want to include extra packages, you can just do
open(TMP,">tmpfile");
print TMP $tmpdata ;
open(RES,"$yourcommand|");
$res = "" ;
while(<RES>){
$res .= $_ ;
}
which is the contrary of what you suggested, but should work also.
I always do it this way if I'm only expecting a single line of output or want to split the result on something other than a newline:
my $result = qx( command args 2>&1 );
my $rc=$?;
# $rc >> 8 is the exit code of the called program.
if ($rc != 0 ) {
error();
}
If you want to deal with a multi-line response, get the result as an array:
my #lines = qx( command args 2>&1 );
foreach ( my $line ) (#lines) {
if ( $line =~ /some pattern/ ) {
do_something();
}
}