2011-08-01 14 views
6

Tengo el siguiente código:¿Cómo se lee la salida del comando JSch?

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]; 
} 

Está colgando tratando de leer desde el lector. ¿Cómo puedo solucionar esto? ¿Cómo voy a buscar lo que está pasando?

+0

La suspensión se debió en realidad a algunas comillas no balanceadas en el comando. –

+0

¿Podría agregar su solución como respuesta en lugar de un comentario? –

Respuesta

14

La suspensión se debió en realidad a algunas comillas no balanceadas en el comando.

Para la posteridad, el código final (después de tratar con algunos otros temas) es:

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

¿cómo esperas que se cierre el canal? ¿Encuetras channel.isClosed()? – coderatchet

+0

@Noel Yap: ¿podría por favor elaborar el método waitForChannelClosed (channel); – Shibankar

+1

Ver la respuesta aquí http://stackoverflow.com/questions/16298279/never-ending-of-reading-server-response-using-jsch/16319567#16319567 – Damienknight

0

La respuesta aceptada es erróneo.

Uno tiene que leer la salida continuamente, mientras espera que el comando termine. De lo contrario, si el comando produce suficiente salida para completar un búfer de salida, el comando se bloqueará, esperando que se consuma el búfer, lo que nunca ocurre. Entonces te encuentras en un punto muerto.

El siguiente ejemplo muestra tanto stdout como stderr de forma continua, mientras se supervisa un estado de comando. Se basa en el official JSch exec.java example (solo agrega una lectura de 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(); 

Si agrega while (!channel.isClosed()) {} después de la channel.connect();, se verá que con una cantidad suficientemente grande i en la cáscara for bucle (10000 es suficiente con en mi entorno), el bucle no termina nunca.

Cuestiones relacionadas