为什么子进程的输出顺序错误?
我有一个 Java 程序,它作为子进程以交互模式执行 sh
。输入从 System.in
复制,输出复制到 System.out
。一切工作正常,除了在这个交互式 shell 中运行诸如 pwd
之类的命令时,输出以错误的顺序出现,例如:
$ pwd
$ /home/viz/workspace
而不是
$ pwd
/home/viz/workspace
$
区别在于,在第一种情况下,提示符 $< /code> 在
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();
}
}
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();
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
因为标准错误和标准输出进入不同的线程,异步打印读取的数据。如果您重定向
2>&1
,它可能会起作用,但我不确定它是否可以与Runtime.exec
一起使用(可能会导致“文件未找到 - 2>”) &1”)。因此,您可以创建一个调用sh
并重定向其输出的 shell 脚本,并使用Runtime.exec
调用该脚本:
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 withRuntime.exec
(may cause "file not found - 2>&1"). So you can make a shell script which callssh
and redirects its output, and call that script usingRuntime.exec
:and