简体   繁体   中英

How do I pipe input into a java program, but have that input still show in the output?

Let's say I have a program that asks for three numbers using scanner, something like this:

Scanner console = new Scanner(System.in);
int[] numbers = new int[3];
System.out.println("Hello!");
for (int i = 0; i<3; i++){
    System.out.print("Please enter a number: ");
    numbers[i] = console.nextInt();
}

I want to test a program like this by redirecting some input to it, and then redirecting the output to a file.

input.txt

3
4
5

command

java program < input.txt > output.txt

The problem is that the output.txt will look something like this

Hello!
Please enter a number: Please enter a number: Please enter a number: 

As opposed to something like this

Hello!
Please enter a number: 3
Please enter a number: 4
Please enter a number: 5

Is there any way to make output.txt look more like the second one? I'm on a Mac, if that changes anything.

I do NOT want to modify the code - I have to run this test for a lot of similar programs.

Why your program doesn't work as expected

In your output, the strings "Please enter a number:" are chained without newlines, because you don't print the newlines in the program. When the program is running in interactive mode, the user enters the newlines.

There are no numbers in the output file, because your program doesn't print them to the standard output. Again, when the program is running in interactive mode, the user enters the numbers, but not the program. In the case of redirected output, the numbers coming from the input file are read by the program, but never printed to the standard output.

The correct way

You should check if the program is running in interactive mode (when the input is read from a TTY).

test/MyApp.java

package test;

import java.util.Scanner;
import java.io.Console;

class MyApp {
    public static void main(String args[]) {
        Scanner scanner = new Scanner(System.in);
        Console console = System.console();

        int[] numbers = new int[3];
        for (int i = 0; i < 3; i++){
            if (console != null) {
                System.out.print("Please enter a number: ");
            }
            numbers[i] = scanner.nextInt();
            System.out.printf("Number: %d\n", numbers[i]);
        }
    }
}

Testing

$ printf '%d\n%d\n%d\n' 1 2 3 > file
$ javac -cp . test/MyApp.java
$ java -cp . test/MyApp < file > out
$ cat out
Number: 1
Number: 2
Number: 3

What you may do to have the mixed values for inputs and outputs is :

1) Create your own application, which will call the main method of the application to test (provided all applications have the same package and main class name, or you would have to give this info to your own program, and use reflection to invoke the other program) .

Your application will perform the following steps :

2) Store the regular System InputStream :

InputStream oldInputStream = System.in;

3) Create your own subclass of InputStream (let's call it YourCustomInputStream ), and implement the different read methods, to print what was read from System.in to System.out , and also return the value.

eg :

@Override
public int read(){

    int readInt = oldInputStream.read();
    System.out.println(readInt);
    return readInt;

}

4) Replace the System's input by your own stream :

 System.setIn(new YourCustomInputStream());

5) Call the main method of the application to test.

First I wanted to merge stdout and stderr like this:

while read -r num; do
   sleep 1
   echo ${num}>&2
   echo ${num}
done < input.txt | java program

This will fail when you want to redirect the result to a file.

So can you try the next construction:

while read -r num; do
   sleep 1
   echo ${num}
done < input.txt| tee -a output.txt| java program >> output.txt

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM