Java 为什么子流程的输出顺序错误?

Java 为什么子流程的输出顺序错误?,java,linux,process,stream,Java,Linux,Process,Stream,我有一个Java程序,它以交互模式作为子进程执行sh。输入从System.in复制,输出复制到System.out。除了在这个交互式shell中运行诸如pwd之类的命令时,输出以错误的顺序显示外,其他一切都正常工作,例如: $ pwd $ /home/viz/workspace 而不是 $ pwd /home/viz/workspace $ 不同之处在于,在第一种情况下,提示$在pwd的输出之前打印 你知道为什么会发生这种情况以及如何解决吗 代码如下: import java.io.IOEx

我有一个Java程序,它以交互模式作为子进程执行
sh
。输入从
System.in
复制,输出复制到
System.out
。除了在这个交互式shell中运行诸如
pwd
之类的命令时,输出以错误的顺序显示外,其他一切都正常工作,例如:

$ pwd
$ /home/viz/workspace
而不是

$ pwd
/home/viz/workspace
$
不同之处在于,在第一种情况下,提示
$
pwd
的输出之前打印

你知道为什么会发生这种情况以及如何解决吗

代码如下:

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();
    }
}

因为标准错误和标准输出会转到不同的线程,这些线程异步打印读取的数据。如果重定向
2>&1
,它可能会工作,但我不确定它是否适用于
Runtime.exec
(可能会导致“找不到文件-2>&1”)。因此,您可以创建一个shell脚本,该脚本调用
sh
并重定向其输出,然后使用
Runtime.exec
调用该脚本:

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


如果你运行一个不同的shell会发生什么?@dacwe:到目前为止,我只能让
sh
工作。尝试了bash
bash
,但在尝试执行IO时它被停止。可能它需要一些其他选项(
+m
没有帮助)。但是
$
/home/viz/workspace
都应该在标准输出上输出吗?(所以这里没有比赛.)@dacwe no.从命令行
sh1>temp.log
尝试,然后键入
pwd
。您将看到命令行提示符,但不会看到pwd输出,它将转到
temp.log
。很好!然后是vitaut解决方案!
Runtime.exec("customsh");