1

I need to write a Perl script that pipes input into a Java program. This is related to this, but that didn't help me. My issue is that the Java app doesn't get the print statements until I close the handle. What I found online was that $| needs to be set to something greater than 0, in which case newline characters will flush the buffer. This still doesn't work.

This is the script:

#! /usr/bin/perl -w

use strict;
use File::Basename;

$|=1;

open(TP, "| java -jar test.jar") or die "fail";
sleep(2);

print TP "this is test 1\n";
print TP "this is test 2\n";
print "tests printed, waiting 5s\n";
sleep(5);

print "wait over.  closing handle...\n";
close TP;
print "closed.\n";

print "sleeping for 5s...\n";
sleep(5);
print "script finished!\n";
exit

And here is a sample Java app:

import java.util.Scanner;

public class test{

    public static void main( String[] args ){

        Scanner sc = new Scanner( System.in );
        int crashcount = 0;
        while( true ){
            try{
                String input = sc.nextLine();
                System.out.println( ":: INPUT: " + input );
                if( "bananas".equals(input) ){
                    break;
                }
            } catch( Exception e ){
                System.out.println( ":: EXCEPTION: " + e.toString() );
                crashcount++;
                if( crashcount == 5 ){
                    System.out.println( ":: Looks like stdin is broke" );
                    break;
                }
            }
        }
        System.out.println( ":: IT'S OVER!" );
        return;
    }

}

The Java app should respond to receiving the test prints immediately, but it doesn't until the close statement in the Perl script. What am I doing wrong?

Note: the fix can only be in the Perl script. The Java app can't be changed. Also, File::Basename is there because I'm using it in the real script.

2 Answers 2

3

I've grown rather fond of the IO::Handle derived modules. They make it easy to control flushing, reading data, binary mode, and many other aspects of a handle.

In this case we use IO::File.

use IO::File;

my $tp = IO::File->new( "| java -jar test.jar" )
    or die "fail - $!";

# Manual print and flush
$tp->print( 'I am fond of cake' );
$tp->flush;

# print and flush in one method
$tp->printflush( 'I like pie' );

# Set autoflush ON
$tp->autoflush(1);
$tp->print( 'I still like pie' );

Also, since the file handle is lexically scoped, you don't have to close it manually. It will automatically close when it goes out of scope.

BTW, unless you are targeting a perl older than 5.6, you can use the warnings pragma instead of -w. See perllexwarn for more info.

Sign up to request clarification or add additional context in comments.

Comments

2

$|=1 only works on the currently selected file handle (by default, STDOUT). To make your TP file handle hot you need to do this after opening it:

select(TP);
$| = 1;
select(STDOUT);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.