javapipeprocessbuilderio-redirection

Redirecting the output of a process into the input of another process using ProcessBuilder in Java


I have two processes defined by processBuilders:

ProcessBuilder pb1 = new ProcessBuilder (...)
ProcessBuilder pb2 = new ProcessBuilder (...)

I want the output of pb1 to be the input to pb2. I found in the documentation that I can make the input of pb2 to be read from another process by using pipe:

pb2.redirectInput(Redirect.PIPE);

However, how can I specify that I want this pipe to read from the output of pb1?


Solution

  • static ProcessBuilder.Redirect INHERIT Indicates that subprocess I/O source or destination will be the same as those of the current process.

    static ProcessBuilder.Redirect PIPE Indicates that subprocess I/O will be connected to the current Java process over a pipe.

    So I don't think one of these will help you redirecting the output of one process to the input of another process. You have to implement it yourself.

    Implementation:

    public class RedirectStreams {
    public RedirectStreams(Process process1, Process process2) {
        final Process tmpProcess1 = process1;
        final Process tmpProcess2 = process2;
        new Thread(new Runnable() {
            @Override
            public void run() {
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(tmpProcess1.getInputStream()));
                BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(tmpProcess2.getOutputStream()));
                String lineToPipe;
    
                try {
    
                    while ((lineToPipe = bufferedReader.readLine()) != null){
                        System.out.println("Output process1 / Input process2:" + lineToPipe);
                        bufferedWriter.write(lineToPipe + '\n');
                        bufferedWriter.flush();
                    }
    
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
    
    }
    

    This one can surely be designed nicer and I haven't tested, if it runs's safe, but it does the job.

    Usage:

    RedirectStreams redirectStreams = new RedirectStreams(process1,process2);
    

    Test:

    public class ProcessPipeTest {
    @Test public void testPipe(){
        try {
    
            Process process1 = new ProcessBuilder("/bin/bash").start();
            Process process2 = new ProcessBuilder("/bin/bash").start();
    
            RedirectStreams redirectStreams = new RedirectStreams(process1,process2);
    
            
            BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(process1.getOutputStream()));
            String command = "echo echo echo";
            System.out.println("Input process1: " + command);
            bufferedWriter.write(command + '\n');
            bufferedWriter.close();
    
            
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process2.getInputStream()));
            String actualOutput = bufferedReader.readLine();
            System.out.println("Output process2: " + actualOutput);
            assertEquals("echo",actualOutput);
    
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    }
    

    Output:

    Input process1: echo echo echo

    Output process1 / Input process2:echo echo

    Output process2: echo