How to pipe input to Java program with bash

2020-02-09 06:33发布

My Java program is listening on standard input:

InputStreamReader isReader = new InputStreamReader(System.in);
BufferedReader bufReader = new BufferedReader(isReader);
while(true){
    try {
        String inputStr = null;
        if((inputStr=bufReader.readLine()) != null) {
            ...
        }
        else {
            System.out.println("inputStr is null");
        }
    }
    catch (Exception e) {
        ...
    }
}

Now, I want to pipe input to this program from bash. I tried the following:

echo "hi" | java -classpath ../src test.TestProgram

But it's just printing inputStr is null infinite times. What am I doing wrong?

Edit 1: Updated question to include more code / context.


Edit 2:

Looks like I'm experiencing the same issue as this OP: Command Line Pipe Input in Java

How can I fix the program so that I can pipe input in for testing, but running the program normally will allow users to enter input on standard input as well?

5条回答
Viruses.
2楼-- · 2020-02-09 06:52

You have while(true), so infinite looping is what you're going to get.

Adding a break somewhere in the loop is one way to fix it. But it's not good style, because the reader has to hunt around the loop to find out if and when it exits.

It's much better to make your while statement show clearly what the exit condition is:

String inputStr = "";
while(inputStr != null) {
    inputStr=bufReader.readLine(); 
    if(inputStr != null) {
        ...
    } else {
        System.out.println("inputStr is null");
    }
}
查看更多
你好瞎i
3楼-- · 2020-02-09 06:53

I like slim's answer, only I tend handle it a bit differently. this is a basic template I use for reading a stream of text, line by line.

try {
    // Wrap the System.in inside BufferedReader
    // But do not close it in a finally block, as we 
    // did no open System.in; enforcing the rule that
    // he who opens it, closes it; leave the closing to the OS.
    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    String line;
    while ((line = in.readLine()) != null) {
        // TODO: Handle input line
    }

    // Null was received, so loop was aborted.

} catch (IOException e) {
    // TODO: Add error handler
}

If I am reading a file, I change it slightly, to close the file like this

try {
    File file = new File("some_file.txt");

    // Wrap the System.in inside BufferedReader
    // But do not close it in a finally block, as we
    // did no open System.in; enforcing the rule that
    // he who opens it, closes it; leaves the closing to the OS.
    BufferedReader in = new BufferedReader(new FileReader(file));
    try {
        String line;
        while ((line = in.readLine()) != null) {
            // TODO: Handle input line
        }

        // Null was received, so loop was aborted.

    } finally {
        try {
            in.close();
        } catch (IOException e) {
        }
    }

} catch (IOException e) {
    // TODO: Add error handler
}
查看更多
▲ chillily
4楼-- · 2020-02-09 06:56

You may consider using named pipes (fifos) to allow both normal input via the controlling terminal /dev/tty (or /dev/stdin) and piped input via an input fifo.

See: Redirecting input of application (java) but still allowing stdin in BASH

查看更多
倾城 Initia
5楼-- · 2020-02-09 07:13

Fixed it. After the piping of input was completed, readLine() kept returning null, so the infinite loop kept looping.

The fix is to break from the infinite loop when readLine() returns null.

查看更多
小情绪 Triste *
6楼-- · 2020-02-09 07:15

What am I doing wrong?

I see no reason why the snippet would behave that way. I suspect that the problem is in something that you haven't shown us ...

For instance, which version of echo are you using? The shell builtin? The standard one in '/bin'? Some funky one on your search path?

You could try some simple experiments to determine if the problem is at the shell / command level or within the Java application; e.g.

$ echo hi > tmp
$ cat tmp
$ java -classpath ../src test.TestProgram < tmp
$ cat tmp | java -classpath ../src test.TestProgram

etcetera.

If none of those experiments yield any clues, post the real Java source code of a small program that demonstrates your problem.

(And as @trashgod rightly points out, you might have "fat fingered" the build step, and be running a version of the program that no longer matches your source code.)

查看更多
登录 后发表回答