How to read JSch command output?

I have the following code:

JSch jsch = new JSch(); jsch.setKnownHosts(dotSshDir + "/known_hosts"); jsch.addIdentity(dotSshDir + "/id_rsa"); Session session = jsch.getSession(userName, hostname, 22); session.connect(); ChannelExec channel = (ChannelExec) session.openChannel("exec"); channel.setCommand(command); channel.setInputStream(null); channel.setErrStream(System.err); Reader reader = new InputStreamReader(channel.getInputStream()); char[] buf = new char[1024]; int numRead; while ((numRead = reader.read(buf)) != -1) { String readData = String.valueOf(buf, 0, numRead); result.append(readData); buf = new char[1024]; } 

He hangs trying to read from the reader. How to fix it? How do I start a hunt for what is happening?

+6
source share
2 answers

The dangers were actually associated with some unbalanced quotation marks in the command.

For posterity, the final code (after addressing some other issues):

 public String call(String hostname, String[] argv) throws SubprocessException { StringBuffer result = new StringBuffer(); Session session = null; ChannelExec channel = null; try { // TODO: Emit friendly error if ~/.ssh doesn't exist. String dotSshDir = System.getProperty("user.home") + "/.ssh"; String userName = System.getProperty("user.name"); // TODO: Emit friendly error if ~/.ssh/known_hosts doesn't exist. jSch.setKnownHosts(dotSshDir + "/known_hosts"); // TODO: Emit friendly error if ~/.ssh/id_rsa doesn't exist. jSch.addIdentity(dotSshDir + "/id_rsa"); session = jSch.getSession(userName, hostname, 22); session.connect(); channel = (ChannelExec) session.openChannel("exec"); channel.setCommand(Joiner.on(" ").join(argv)); channel.setInputStream(null); InputStream stdout = channel.getInputStream(); InputStream stderr = channel.getErrStream(); channel.connect(); waitForChannelClosed(channel); if (channel.getExitStatus() != 0) { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stderr)); readAll(bufferedReader, result); throw new Exception(result.toString()); } else { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stdout)); readAll(bufferedReader, result); } } catch (Exception e) { throw new SubprocessException(e); } finally { if (channel != null) { channel.disconnect(); } if (session != null) { session.disconnect(); } } return result.toString(); } 
+14
source

The accepted answer is incorrect.

You need to constantly read the output, waiting for the completion of the command. Otherwise, if the command produces enough output to fill the output buffer, the command will freeze, waiting for the buffer to be consumed, which will never happen. This way you get a dead end.

The following example displays both stdout and stderr in sequence, as well as monitoring the status of the command. 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"); InputStream commandOutput = channel.getExtInputStream(); StringBuilder outputBuffer = new StringBuilder(); StringBuilder errorBuffer = new StringBuilder(); 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.append(new String(tmp, 0, i)); } while (err.available() > 0) { int i = err.read(tmp, 0, 1024); if (i < 0) break; errorBuffer.append(new String(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()); System.out.println("error: " + errorBuffer.toString()); channel.disconnect(); 

If you add while (!channel.isClosed()) {} after channel.connect(); , you will see that with a sufficiently large i in the for shell loop (in my environment, 10,000 is enough), the loop never ends.

0
source

Source: https://habr.com/ru/post/894049/


All Articles