Why executing interactive process with redirected input/output streams causes application being stopped?
I have a console Java program that executes sh -i
in a separate process and copies the data between the processes' input/output stream and corresponding System streams:
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 = 0;
byte[] buffer = new byte[4096];
while (-1 != (n = in.read(buffer))) {
out.write(buffer, 0, n);
out.flush();
}
} 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");
new Thread(new StreamCopier(
process.getInputStr开发者_开发技巧eam(), System.out)).start();
new Thread(new StreamCopier(
process.getErrorStream(), System.err)).start();
new Thread(new StreamCopier(
System.in, process.getOutputStream())).start();
process.waitFor();
}
}
Running it under Linux results in the following:
$
[1]+ Stopped java -cp . Test
Could anyone clarify why is the application stopped and how to avoid it?
This is related to my question on copying streams, but I think this particular issue deserves separate attention.
You can turn off job control by invoking the shell like sh -i +m
, which will stop it taking over the tty. This means that the fg
and bg
commands will not work and a Ctrl+Z will suspend your Java application, the shell and all programs started from it.
If you still want job control, you should use a pseudo terminal to communicate with the shell, which creates a new tty for the shell to use, but I don't think Java supports that.
You are being stopped by SIGTTIN or SIGTTOU. These signals are sent to a background process when they attempt to do IO to a TTY. In this case "background" means "not the controlling process group of the terminal". I suspect the subshell you're forking off is creating a new pgrp and taking over your tty. Then the parent program (java) does IO (in your case probably reading from the TTY) and gets SIGTTIN.
An easy way to confirm this theory would be to replace sh with something simpler (not a shell) which will not try to take over the tty.
精彩评论