How to redirect ssh->capture2 output to STDOUT without buffering? - perl

I am using Net::OpenSSH module. The capture2 function returns the output to a variable which I can print to get the output but I want to do this directly to STDOUT without buffering.

Related

IPC::Open2 middleware

I would like to make a wrapper that would take data from STDIN and pass it to another script, wait for his STDOUT response and output it to STDOUT on the parent side.
I have the following code but it does not seems to work:
test.pl
#!/usr/bin/perl
#
use IPC::Open2;
$pid = open2( \*RDR, \*WTR, '/usr/bin/perl test2.pl');
while (<STDIN>) {
print WTR;
}
while (<RDR>) {
print STDOUT;
}
and on the test2.pl, i have:
#!/usr/bin/perl
#
while (<STDIN>) {
print STDOUT;
}
It seems to write to test2.pl but i have no feedback from test2.pl.
Any hints?
Thank's,
You should close WTR when you are done reading from STDIN. Your external command will keep expecting input until you do this, and if you are suffering from buffering, your external program won't terminate and it won't output anything.
You are probably "suffering from buffering" in both your primary script and in your external command.
In your test script, you can add $|=1 to the top of the script to make its output more responsive. You might not be able to affect the output buffering of an arbitrary external command, though.
Update: IPC::Open2 already sets autoflush on the write filehandle, so the external command won't be starved for input.

Perl: Testing an input reader?

Is there a way to automatically test using the standard Test etc. modules whether a Perl program is reading input from e.g. STDIN properly? E.g. testing a program that reads two integers from STDIN and prints their sum.
It's not 100% clear what you mean, I'll asnswer assuming you want to write a test script that tests your main program, which as part of the test needs to have test input data passed via STDIN.
You can easily do that if your program outputs what it reads. You don't need a special test module - simply:
Call your program your're testing via a system call
redirect both STDIN and STDOUT of tested program to your test script, using
IPC::Open2 module to open both sides via pipes to filehandles,
... OR, build your command to redirect to/from files and read/write the files in the test script
Check STDOUT from tested program that you collected in the last step to make sure correct values are printed.
If you want to test if STDIN is connected to a terminal, use -t, as in:
if( -t STDIN ){
print "Input from a terminal\n";
}else{
print "Input from a file or pipe\n";
}
See http://perldoc.perl.org/perlfunc.html#Alphabetical-Listing-of-Perl-Functions

Reopen STDERR/STDOUT to write to combined logfile with timestamps

I basically want to reopen STDERR/STDOUT so they write to one logfile with both the stream and the timestamp included on every line. So print STDERR "Hello World" prints STDERR: 20130215123456: Hello World. I don't want to rewrite all my print statements into function calls, also some of the output will be coming from external processes via system() calls anyway which I won't be able to rewrite.
I also need for the output to be placed in the file "live", i.e. not only written when the process completes.
(p.s. I'm not asking particularly for details of how to generate timestamps, just how to redirect to a file and prepend a string)
I've worked out the following code, but it's messy:
my $mode = ">>";
my $file = "outerr.txt";
open(STDOUT, "|-", qq(perl -e 'open(FILE, "$mode", "$file"); while (<>) { print FILE "STDOUT: \$\_"; }'));
open(STDERR, "|-", qq(perl -e 'open(FILE, "$mode", "$file"); while (<>) { print FILE "STDERR: \$\_"; }'));
(The above doesn't add dates, but that should be trivial to add)
I'm looking for a cleaner solution, one that doesn't require quoting perl code and passing it on the command line, or at least module that hides some of the complexity. Looking at the code for Capture::Tiny it doesn't look like it can handle writing a part of output, though I'm not sure about that. annotate-output only works on an external command sadly, I need this to work on both external commands and ordinary perl printing.
The child launched via system doesn't write to STDOUT because it does not have access to variables in your program. Therefore, means having code run on a Perl file handle write (e.g. tie) won't work.
Write another script that runs your script with STDOUT and STDERR replaced with pipes. Read from those pipes and print out the modified output. I suggest using IPC::Run to do this, because it'll save you from using select. You can get away without it if you combine STDOUT and STDERR in one stream.

How to flush output in backticks In Perl?

If I have this perl app:
print `someshellscript.sh`;
that prints bunch of stuff and takes a long time to complete, how can I print that output in the middle of execution of the shell script?
Looks like Perl will only print the someshellscript.sh result when it completes, is there a way to make output flush in the middle of execution?
What you probably want to do is something like this:
open(F, "someshellscript.sh|");
while (<F>) {
print;
}
close(F);
This runs someshellscript.sh and opens a pipe that reads its output. The while loop reads each line of output generated by the script and prints it. See the open documentation page for more information.
The problem here is that escaping with backticks stores your script to a string, which you then print. For this reason, there would be no way to "flush" with print.
Using the system() command should print output continuously, but you won't be able to capture the output:
system "someshellscript.sh";

Is there a way to output debug messages in Perl that are not piped?

Is there a way to output debug messages in Perl that are not piped? I have a Perl script that I use in a pipe but I really want to print some diagnostic information to the screen instead of to the pipe.
Are you piping both stdout and stderr? If not, write to the one you're not piping :)
e.g.
print STDERR "This goes to standard error";
print STDOUT "This goes to standard output";
(If you don't provide a handle, STDOUT is the default of course - unless you've asked Perl to use a different default handle...)
Unless you have said something like 2>&1 on the commandline, STDERR should show up on the screen. You can write to STDERR like Jon Skeet suggests or you can use the warn function.