Perl expect output of executed command - perl

i wrote a little script which executes the ls command. Now I want to store the output of that command in a variable to work with it in the further perl script. Unfortunately I cannot grab the output from the ls command.
my ($core) = "servername";
my $tel_con = "ssh ".$core. " -l $user";
$ssh = Expect->spawn("$tel_con");
$ssh->log_stdout(1);
unless ( $ssh->expect( 5, -re => '$' ) ) {
return "Never connected " . $ssh->exp_error() . "\n";
}
sleep 1;
$ssh->send_slow(0, "ls -l\r");
$ssh->clear_accum();
my $str = $ssh->exp_after();
print "STR = '$str'\n";
Maybe you can give me some help please?

use Net::OpenSSH;
my $ssh = Net::OpenSSH->new($core, user => $user);
$ssh->error and die $ssh->error;
my $output = $ssh->capture('ls -l');
print "command output:\n$output\n\n";

In case you can not or don't want to use Net::OpenSSH you may do:
my #output = $exp->expect(5);
print 'OUT: '.$output[3].'END';
To get the whole output (including the used command, return string, console information)

you could call expect in a seperate process and grab the output via qx or open a pipe

What is send_slow? Depending on how this command sends the ls command, the output can be received in different ways.
Most probably, the error output of the command is stored in the $? variable, possibly byte-shifted.

It seems that Expect will redirect everything to STDOUT and log it internally. Since you enabled output with $ssh->log_stdout(1), you should be able to get the results of ls -l directly from STDOUT (maybe by redirecting standard out to a variable). You can also see try grab the data from the internal logging. Just make sure to grab the output before doing clear_accum().
From CPAN: $object->send_slow($delay, #strings);
... After each character $object will be checked to determine whether or not it has any new data ready and if so update the accumulator for future expect() calls and print the output to STDOUT and #listen_group if log_stdout and log_group are appropriately set.

Layman's terms?
I must obligatorily post this link - I still go there from time-to-time, it is the most layman-y explanation I've ever found of all things regex:
http://www.anaesthetist.com/mnm/perl/Findex.htm

Related

Copy output and extract number from it in perl

I am working on a perl script in which I will run a command and get a output like : your id is <895162>. I will store this string and read the number from this string only . The problem is my main command will run in shell using the system command from perl .
like :
#ids.csh is "echo your id is <1123221>"
my $p = system ("./ids.csh 2>&1 > /dev/null");
print "$p\n";
$p =~ s/[^0-9]//g;
but the output is not copying to the $p file , Where I am going wrong ?
system runs a command but doesn't capture it. For that, you want qx/backticks:
my $p = `./ids.csh 2>/dev/null`;
As Len Jaffe said, you probably want to throw away stderr output (rather than displaying it to your screen or wherever your stderr is going), but not stdout (that contains the message you want to capture).
Note that when qx fails, it can do so for several different reasons and constructing a meaningful error message is not trivial. If you run into problems, consider using IPC::System::Simple's capture() instead.
You have redirected all of the output to /dev/null, which means that all of your output is being discarded.
I think you probably mean:
./ids.csh 2>/dev/null
Which will redirect stderr to /dev/null while leaving stdout unchanged.

stop console output from unix command execution in perl

I am running unix commands in perl as
$cmd="ls -l";
$result=`$cmd`;
print $log_file $result;
but the output from execution is also printed on screen.
how to execute command without printing result on screen ?
The standard output stream isn't printed to screen -- it's captured to $result. But there is a second output stream called the standard error stream that programs can write to, and which also by default goes to the screen. Many programs use this stream for logging, or (in the case of ls) for writing error messages. To capture this in addition, use
$cmd = "ls -l 2>&1";
To discard it instead, use
$cmd = "ls -l 2>/dev/null";
I think there's a mistake. Try that in a shell:
perl -e 'my $x = `ls -l`;'
That doesn't produce any output.
it happens probably because $log_file is somehow attached to STDOUT, duplicated to it, something like:
open(my $log_file, ">&STDOUT")

command output is directed to the screen

novice Perl programmer here!.
I'm using the system() function to get the return code for an external program (in this case - php), however, the command's output is still printed to the screen.
How do I prevent it from doing so?
My code is:
use strict; use warnings;
print 'Return code:', system('php -l wrong.php'), "\n";
This code does print the return code, but it also print the the output of the command executed.
Any help will be appreciated!
EDIT: further testing shown that this happens while only using the php lint command.. using it with other commands doesnt print anything...
What you want is IPC::Open3:
use IPC::Open3;
use Symbol qw(gensym);
my $err = gensym; #work around IPC::Open3's interface
my $pid = open3 my $wtr, my $rdr, $err,
'some cmd', 'arg1', 'arg2', ...;
The separates out stdin into $wtr, stdout into $rdr, and stderr into $err
This also gives you maximum control over communicating with the process
If you are on a UNIX-like OS, you should be able to redirect the output in the command:
Try:
system('php -l wrong.php >> /dev/null') to get rid of what's being sent to stdout.
You could also open the command with a pipe to handle the output directly, which should be more portable.

Why can't I get the output of a command with system() in Perl?

When executing a command on the command-line from Perl, is there a way to store that result as a variable in Perl?
my $command = "cat $input_file | uniq -d | wc -l";
my $result = system($command);
$result always turns out to be 0.
Use "backticks":
my $command = "cat $input_file | uniq -d | wc -l";
my $result = `$command`;
And if interested in the exit code you can capture it with:
my $retcode = $?;
right after making the external call.
From perlfaq8:
Why can't I get the output of a command with system()?
You're confusing the purpose of system() and backticks (````). system() runs a command and returns exit status information (as a 16 bit value: the low 7 bits are the signal the process died from, if any, and the high 8 bits are the actual exit value). Backticks (``) run a command and return what it sent to STDOUT.
$exit_status = system("mail-users");
$output_string = `ls`;
You can use the Perl back-ticks to run a shell command, and save the result in an array.
my #results = `$command`;
To get just a single result from the shell command, you can store it in a scalar variable:
my $result = `$command`;
If you are expecting back multiple lines of output, it's easier to use an array, but if you're just expecting back one line, it's better to use scalar.
(something like that, my perl is rusty)
You can use backticks, as others have suggested. That's fine if you trust whatever variables you're using to build your command.
For more flexibility, you can open the command as a pipe and read from that as you would a file. This is particularly useful when you want to pass variables as command line arguments to the program and you don't trust their source to be free of shell escape characters, as open in recent Perl (>= 5.8) has the capacity to invoke a program from an argument list. So you can do the following:
open(FILEHANDLE, '-|', 'uniq', 'some-file.txt') or die "Cannot fork: $!\n";
while (<FILEHANDLE>) {
# process a line from $_
}
close FILEHANDLE or die "child error: $!\n";
IPC::System::Simple provides the 'capture' command which provides a safe, portable alternative to backticks. It (and other commands from this module) are highly recommended.
I'm assuming this a 'contrived' example, because this is
equivalent: 'uniq -d $input_file | wc -l'.
In almost all my experience, the only reason for putting the results
in to a perl variable, is to parse the later. In that case, I use
the following pattern:
$last = undef;
$lc = 0;
open(FN, "$input_file");
while (<FN>) {
# any other parsing of the current line
$lc++ if ($last eq $_);
$last = $_;
}
close(FN);
print "$lc\n";
This also has the added advantages:
no fork for shell, cat, uniq, and wc
faster
parse and collect the desired input

How can I pass arguments from one Perl script to another?

I have a script which I run and after it's run it has some information that I need to pass to the next script to run.
The Unix/DOS commands are like so:
perl -x -s param_send.pl
perl -x -s param_receive.pl
param_send.pl is:
# Send param
my $send_var = "This is a variable in param_send.pl...\n";
$ARGV[0] = $send_var;
print "Argument: $ARGV[0]\n";
param_receive.pl is:
# Receive param
my $receive_var = $ARGV[0];
print "Parameter received: $receive_var";
But nothing is printed. I know I am doing it wrong but from the tutorials I can't figure out how to pass a parameter from one script to the next!
You can use a pipe character on the command line to connect stdout from the first program to stdin on the second program, which you can then write to (using print) or read from (using the <> operator).
perl param_send.pl | perl param_receive.pl
If you want the output of the first command to be the arguments to the second command, you can use xargs:
perl param_send.pl | xargs perl param_receive.pl
The %ENV hash in Perl holds the environment variables such as PATH, USER, etc. Any modifications to these variables is reflected 'only' in the current process and any child process that it may spawn. The parent process (which happens to be the shell in this particular instance) does not reflect these changes so when the 'param_send.pl' script ends all changes are lost.
For e.g. if you were to do something like,
#!/usr/bin/perl
# param_send.pl
$ENV{'VAL'} = "Value to send to param_recv";
#!/usr/bin/perl
# param_recv.pl
print $ENV{'VAL'};
This wouldn't work since VAL is lost when param_send exits. One workaround is to call param_recv.pl from param_send.pl and pass the value as an environment variable or an argument,
#!/usr/bin/perl
# param_send.pl
$ENV{'VAL'} = "Value to send to param_recv";
system( $^X, "param_recv.pl");
OR
#!/usr/bin/perl
# param_send.pl
system( $^X, qw(param_recv.pl 'VAL') );
Other options include piping the output or you could check out this Perlmonks node for a more esoteric solution.
#ARGV is created at runtime and does not persist. So your second script will not be able to see the $ARGV[0] you assigned in the first script. As crashmstr points out you either need to execute the second script from the first using one of the many methods for doing so. For example:
my $send_var = "This is a variable in param_send.pl...\n";
`perl param_receive.pl $send_var`;
or use an environment variable using %ENV:
my $send_var = "This is a variable in param_send.pl...\n";
$ENV['send_var'] = $send_var;
For a more advanced solutions think about using sockets or IPC.