One has to read the output continuously, while waiting for the command to finish. Otherwise, if the command produces enough output to fill in an output buffer, the command will hang, waiting for the buffer to be consumed, what never happens. So you get a deadlock.
The following example reads both stdout and stderr continuously, while monitoring a command status. It is based on the official JSch exec.java
example (just adds a reading of stderr).
ChannelExec channel = (ChannelExec)session.openChannel("exec");
channel.setCommand(
"for((i=1;i<=10000;i+=2)); do echo "Long output - $i"; done ; " +
"echo error output >&2");
ByteArrayOutputStream outputBuffer = new ByteArrayOutputStream();
ByteArrayOutputStream errorBuffer = new ByteArrayOutputStream();
InputStream in = channel.getInputStream();
InputStream err = channel.getExtInputStream();
channel.connect();
byte[] tmp = new byte[1024];
while (true) {
while (in.available() > 0) {
int i = in.read(tmp, 0, 1024);
if (i < 0) break;
outputBuffer.write(tmp, 0, i);
}
while (err.available() > 0) {
int i = err.read(tmp, 0, 1024);
if (i < 0) break;
errorBuffer.write(tmp, 0, i);
}
if (channel.isClosed()) {
if ((in.available() > 0) || (err.available() > 0)) continue;
System.out.println("exit-status: " + channel.getExitStatus());
break;
}
try {
Thread.sleep(1000);
} catch (Exception ee) {
}
}
System.out.println("output: " + outputBuffer.toString("UTF-8"));
System.out.println("error: " + errorBuffer.toString("UTF-8"));
channel.disconnect();
If you add while (!channel.isClosed()) {}
after the channel.connect();
, you will see that with a sufficiently large i
in the shell for
loop (10000 is enough with in my environment), the loop never finishes.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…