2011-08-01 175 views
6

我有以下代码:如何阅读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]; 
} 

它是挂着羊头从读者阅读。我该如何解决?我该如何去寻找发生的事情?

+0

悬挂实际上是由于命令中的一些不平衡的引号引起的。 –

+0

您可以将您的解决方案作为答案而不是评论添加吗? –

回答

14

悬挂实际上是由于命令中的一些不平衡的引号引起的。

为后人,最终代码(处理一些其他问题后):

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

你如何等待频道关闭?你轮询channel.isClosed()? – coderatchet

+0

@Noel Yap:请稍微详细说明方法waitForChannelClosed(channel); – Shibankar

+1

请参阅这里的答案http://stackoverflow.com/questions/16298279/never-ending-of-reading-server-response-using-jsch/16319567#16319567 – Damienknight

0

接受的答案是错的。

在等待命令完成时,必须连续读取输出。否则,如果该命令产生足够的输出来填充输出缓冲区,该命令将挂起,等待缓冲区被消耗,从未发生过。所以你会陷入僵局。

以下示例在监视命令状态的同时连续读取stdout和stderr。它基于official JSch exec.java example(只是增加了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(); 

如果您在channel.connect();之后添加while (!channel.isClosed()) {},你会看到一个足够大的i在外壳for环(10000就够了,在我的环境),循环永远不会完成。