how to get text via backticks or system in Perl - perl

I want to call a EXE file in Perl which performs some action
I tried calling the exe file via backtick and system but in both the cases i get only the return value
The exe file prints some text on to the console. Is it possible to capture that as well?
I looked into this variable ${^CHILD_ERROR_NATIVE} but I get only the return value and not text
I am using Perl 5.14
Thanks in advance

The application might not print its output to STDOUT but STDERR instead, which isn't captured by the backtick operator. To capture both, you could use the following:
my $binary = 'foo.exe';
my $output = `$binary 2>&1`;
For a more fine-tuned capturing, you might want to resort to IPC::Open3 with which you can "control" all of a process' streams (IN, OUT and ERR).

I used to execute commands from perl script and capture the output this way
sub execute_command() {
my($host) = #_;
open(COMMAND_IN, "your_command |");
while (<COMMAND_IN>)
{ #The COMMAND_IN will have the output of the command
#Read the output of your command here...
$ans = $_;
}
close(COMMAND_IN);
return $ans;
}
Check whether it helps you

I recommend the capture and capture_err functions from Scriptalicious.
use Scriptalicious qw(capture);
my $output = capture('my_command', 'arg');

Related

Perl -> How return value of qx(perl file)

I need to know how is possible return values of Perl file from other Perl file.
In my first file i call to the second file with sentence similar to:
$variable = qx( perl file2.pl --param1 $p1 --param2 $p2);
I have tried with exit and return to get this data but is not possible.
Any idea?
Processes are no subroutines.
Communication between processes (“IPC”) is mostly done via normal file handles. Such file handles can specifically be
STDIN and STDOUT,
pipes that are set up by the parent process, these are then shared by the child,
sockets
Every process also has an exit code. This code is zero for success, and non-zero to indicate a failure. The code can be any integer in the range 0–255. The exit code can be set via the exit function, e.g. exit(1), and is also set by die.
Using STDIN and STDOUT is the normal mode of operation for command line programs that follow the Unix philosophy. This allows them to be chained with pipes to more complex programs, e.g.
cat a b c | grep foo | sort >out
Such a tool can be implemented in Perl by reading from the ARGV or STDIN file handle, and printing to STDOUT:
while (<>) {
# do something with $_
print $output;
}
Another program can then feed data to that script, and read it from the STDOUT. We can use open to treat the output as a regular file handle:
use autodie;
open my $tool, "-|", "perl", "somescript.pl", "input-data"; # notice -| open mode
while (<$tool>) {
...
}
close $tool;
When you want all the output in one variable (scalar or array), you can use qx as a shortcut: my $tool_output = qx/perl somescript.pl input-data/, but this has two disadvantages: One, a shell process is executed to parse the command (shell escaping problems, inefficiency). Two, the output is available only when the command has finished. Using open on the other hand allows you to do parallel computations.
In file2.pl, you must print something to STDOUT. For example:
print "abc\n";
print is the solution.
Sorry for my idiot question!
#
$variable = system( perl file2.pl --param1 $p1 --param2 $p2);
#$variable has return value of perl file2.pl ...

Perl Capture and Modify STDERR before it prints to a file [duplicate]

I want to execute an external command from within my Perl script, putting the output of both stdout and stderr into a $variable of my choice, and to get the command's exit code into the $? variable.
I went through solutions in perlfaq8 and their forums, but they're not working for me. The strange thing is that I don't get the output of sdterr in any case, as long as the exit code is correct.
I'm using Perl version 5.8.8, on Red Hat Linux 5.
Here's an example of what I'm trying:
my $cmd="less";
my $out=`$cmd 2>&1`;
or
my $out=qx($cmd 2>&1);
or
open(PIPE, "$cmd 2>&1|");
When the command runs successfully, I can capture stdout.
I don't want to use additional capture modules. How can I capture the full results of the external command?
This was exactly the challenge that David Golden faced when he wrote Capture::Tiny. I think it will help you do exactly what you need.
Basic example:
#!/usr/bin/env perl
use strict;
use warnings;
use Capture::Tiny 'capture';
my ($stdout, $stderr, $return) = capture {
system( 'echo Hello' );
};
print "STDOUT: $stdout\n";
print "STDERR: $stderr\n";
print "Return: $return\n";
After rereading you might actually want capture_merged to join STDOUT and STDERR into one variable, but the example I gave is nice and general, so I will leave it.
Actually, the proper way to write this is:
#!/usr/bin/perl
$cmd = 'lsss';
my $out=qx($cmd 2>&1);
my $r_c=$?;
print "output was $out\n";
print "return code = ", $r_c, "\n";
You will get a '0' if no error and '-1' if error.
STDERR is intended to be used for errors or messages that might need to be separated from the STDOUT output stream. Hence, I would not expect any STDERR from the output of a command like less.
If you want both (or either) stream and the return code, you could do:
my $out=qx($cmd 2>&1);
my $r_c=$?
print "output was $out\n";
print "return code = ", $r_c == -1 ? $r_c : $r_c>>8, "\n";
If the command isn't executable (perhaps because you meant to use less but wrote lsss instead), the return code will be -1. Otherwise, the correct exit value is the high 8-bits. See system.
A frequently given answer to this question is to use a command line containing shell type redirection. However, suppose you want to avoid that, and use open() with a command and argument list, so you have to worry less about how a shell might interpret the input (which might be partly made up of user-supplied values). Then without resorting to packages such as IPC::Open3, the following will read both stdout and stderr:
my ($child_pid, $child_rc);
unless ($child_pid = open(OUTPUT, '-|')) {
open(STDERR, ">&STDOUT");
exec('program', 'with', 'arguments');
die "ERROR: Could not execute program: $!";
}
waitpid($child_pid, 0);
$child_rc = $? >> 8;
while (<OUTPUT>) {
# Do something with it
}
close(OUTPUT);

Capturing standard out of a program to a file-like object?

I'm trying to capture standard output of a command to a file-like object in Perl.
I essentially need to do the following:
Execute an OS command, capturing standard output.
Run a regular expression on each line of the file and pull output into an array.
Call another OS command for each item in the array of lines of output from the first command.
How can I do step one? I'd like to execute a command and get its standard out in a filelike object so as to be able to read it line by line.
The first part is easy:
use autodie qw(:all);
open my $input, '-|', 'os-command', #args;
Clearly, the remainder is not much harder:
while (<$input>)
{
next unless m/your regex/;
system 'other-command', $_;
}
Automatic error checking for the open and system calls is provided through autodie.
You might do:
my #input = qx( some_command );
for my $line (#input) {
$line =~ m{some_pattern} and system("some_command", "$line");
}

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: $_";
}

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();
}
}