Why is the output from subprocess in wrong order?

2019-09-12 11:57发布

I have a Java program that executes sh in interactive mode as a subprocess. The input is copied from System.in and output is copied to System.out. Everything works fine except that when running commands such as pwd in this interactive shell the output appears in a wrong order, for example:

$ pwd
$ /home/viz/workspace

instead of

$ pwd
/home/viz/workspace
$

The difference is that in the first case the prompt $ is printed before the output from pwd.

Any ideas why does it happen and how to fix it?

Here is the code:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

class StreamCopier implements Runnable {
    private InputStream in;
    private OutputStream out;

    public StreamCopier(InputStream in, OutputStream out) {
        this.in = in;
        this.out = out;
    }

    public void run() {
        try {
            int n;
            byte[] buffer = new byte[4096];
            while ((n = in.read(buffer)) != -1) {
                out.write(buffer, 0, n);
                out.flush();
            }
            out.close();
        }
        catch (IOException e) {
            System.out.println(e);
        }
    }
}

public class Test {
    public static void main(String[] args)
            throws IOException, InterruptedException {
        Process process = Runtime.getRuntime().exec("sh -i +m");
        Thread outThread = new Thread(new StreamCopier(
                process.getInputStream(), System.out));
        outThread.start();
        Thread errThread = new Thread(new StreamCopier(
                process.getErrorStream(), System.err));
        errThread.start();
        Thread inThread = new Thread(new StreamCopier(
                System.in, process.getOutputStream()));
        inThread.start();
        process.waitFor();
        outThread.join();
        errThread.join();
        inThread.join();
    }
}

1条回答
smile是对你的礼貌
2楼-- · 2019-09-12 12:48

Because standard error and standard output go to different threads which print the read data asynchronously. It might work, if you redirect 2>&1, but I'm not sure it will work with Runtime.exec (may cause "file not found - 2>&1"). So you can make a shell script which calls sh and redirects its output, and call that script using Runtime.exec:

#!/bin/sh
sh -i +m 2>&1

and

Runtime.exec("customsh"); 
查看更多
登录 后发表回答