How to execute interactive commands and read their sparse output from Java using JSch

萝らか妹 提交于 2020-06-25 05:35:13

问题


Currently I can use the JSch library to execute remote commands in a SSH session like this:

JSch jsch = new JSch();
Session session = jsch.getSession(username, host, 22);
session.setPassword(password);

Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);

session.connect();

ChannelExec channel = (ChannelExec) session.openChannel("exec");
BufferedReader in = new BufferedReader(new InputStreamReader(channel.getInputStream()));

channel.setCommand("ls -l");
channel.connect();

StringBuilder output = new StringBuilder();

String s = null;
while((s = in.readLine()) != null){
    output.append(s + "\n");
}

System.out.println(output);

The commands that returns the full value right away works fine, but some interactive commands (like "Docker run") returns values every second or so (for a couple of minutes), and the previous code only read the first value returned.

Is there any way to read the values as they are returned by the command?


EDIT

This is my code now:

public String executeCommand(String cmd) {
    try {
        Channel channel = session.openChannel("shell");

        OutputStream inputstream_for_the_channel = channel.getOutputStream();
        PrintStream commander = new PrintStream(inputstream_for_the_channel, true);

        channel.setOutputStream(System.out, true);

        channel.connect();

        commander.println(cmd);

        commander.close();

        do {
            Thread.sleep(1000);
        } while(!channel.isEOF());
    } catch(Exception e) {
        e.printStackTrace();
    }
    return null;
}

回答1:


The way the JSch getInputStream is implemented, its read seems to return -1 not only when the session/channel closes, but also when there's momentarily no input data.

Your should better use channel.isClosed() to test if session/channel closed. See examples/Sudo.java:

byte[] tmp=new byte[1024];
while(true){
  while(in.available()>0){
    int i=in.read(tmp, 0, 1024);
    if(i<0)break;
    System.out.print(new String(tmp, 0, i));
  }
  if(channel.isClosed()){
    System.out.println("exit-status: "+channel.getExitStatus());
    break;
  }
  try{Thread.sleep(1000);}catch(Exception ee){}
}

Your code with "shell" channel prints the output on console, because you have instructed it so by:

channel.setOutputStream(System.out, true);

You have to implement the output stream to write to a string. See Get an OutputStream into a String

Or actually, you should be able to use the same code as with the "exec" channel.



来源:https://stackoverflow.com/questions/29899720/how-to-execute-interactive-commands-and-read-their-sparse-output-from-java-using

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!