Java 如何在字符串中获取jsch shell命令输出

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25789245/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 01:08:15  来源:igfitidea点击:

How to get jsch shell command output in String

javasshjsch

提问by vishy

I am using a JSCH -SSH library to execute command in "shell" channel, but unable to find a way to do 2 things:-

我正在使用 JSCH -SSH 库在“shell”通道中执行命令,但无法找到做两件事的方法:-

1) How to find whether the command is completely executed on remote unix box ?

1)如何查看命令是否在远程unix box上完全执行?

2) How to capture the command output in String , instead of printing it on System.out console ?

2) 如何在 String 中捕获命令输出,而不是在 System.out 控制台上打印它?

Below is my code snippet which works fine to display shell command output on system.out

下面是我的代码片段,它可以很好地在 system.out 上显示 shell 命令输出

NOTE :I do NOT want to use ,"exec" channel, as it starts a new process for each command and does not remember "session" variables which were exported. I must use "shell" channel.

注意:我不想使用“exec”通道,因为它会为每个命令启动一个新进程,并且不记得导出的“会话”变量。我必须使用“shell”通道。

Below is my code snippet. Any help is appreciated.Thanks for your time.

下面是我的代码片段。任何帮助表示赞赏。感谢您的时间。

try{

  String commandToRun = "ls /tmp/*.log \n";
  if(channel.isClosed())
      channel=session.openChannel("shell");
  byte[] bytes = commandToRun.getBytes();
  ByteArrayInputStream bais=new ByteArrayInputStream(bytes);
  channel.setInputStream(bais);
  InputStream ins=channel.getInputStream();
  channel.connect();
  channel.setOutputStream(System.out);//This prints on console. Need 2 capture in String somehow?

  //in-efficient way to allow command to execute completely on remote Unix machine
  //DO NOT know a better way, to know when command is executed completely
  Thread.sleep(5000L);
}
 catch(Exception e){
  System.out.println("Exception  in executeCommand() --->"+ e.getMessage());
  e.printStackTrace();
}

采纳答案by Nikola Dimitrovski

For 2) u can use ByteArrayOutputStream

对于 2) 你可以使用 ByteArrayOutputStream

final ByteArrayOutputStream baos = new ByteArrayOutputStream();
channel.setOutputStream(baos);

and then create new string from new String(baos.toByteArray())

然后从中创建新字符串 new String(baos.toByteArray())

For 1 have you tried to use 2>&1 at the end of your command?

对于 1,您是否尝试在命令末尾使用 2>&1 ?

String commandToRun = "ls /tmp/*.log 2>&1 \n";

回答by Mihail

My solution may not be needed anymore for the OP, but anyone else who is searching for a solution to cover both conditions 1) waiting for the commands to finish on remote machine; and 2) capturing output as string; you can try this:

OP 可能不再需要我的解决方案,但是任何其他正在寻找解决方案以涵盖这两种情况的人 1) 等待命令在远程机器上完成;和 2) 将输出捕获为字符串;你可以试试这个:

public class SshConnectionManager {

private static Session session;
private static ChannelShell channel;
private static String username = "";
private static String password = "";
private static String hostname = "";


private static Session getSession(){
    if(session == null || !session.isConnected()){
        session = connect(hostname,username,password);
    }
    return session;
}

private static Channel getChannel(){
    if(channel == null || !channel.isConnected()){
        try{
            channel = (ChannelShell)getSession().openChannel("shell");
            channel.connect();

        }catch(Exception e){
            System.out.println("Error while opening channel: "+ e);
        }
    }
    return channel;
}

private static Session connect(String hostname, String username, String password){

    JSch jSch = new JSch();

    try {

        session = jSch.getSession(username, hostname, 22);
        Properties config = new Properties(); 
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);
        session.setPassword(password);

        System.out.println("Connecting SSH to " + hostname + " - Please wait for few seconds... ");
        session.connect();
        System.out.println("Connected!");
    }catch(Exception e){
        System.out.println("An error occurred while connecting to "+hostname+": "+e);
    }

    return session;

}

private static void executeCommands(List<String> commands){

    try{
        Channel channel=getChannel();

        System.out.println("Sending commands...");
        sendCommands(channel, commands);

        readChannelOutput(channel);
        System.out.println("Finished sending commands!");

    }catch(Exception e){
        System.out.println("An error ocurred during executeCommands: "+e);
    }
}

private static void sendCommands(Channel channel, List<String> commands){

    try{
        PrintStream out = new PrintStream(channel.getOutputStream());

        out.println("#!/bin/bash");
        for(String command : commands){
            out.println(command);
        }
        out.println("exit");

        out.flush();
    }catch(Exception e){
        System.out.println("Error while sending commands: "+ e);
    }

}

private static void readChannelOutput(Channel channel){

    byte[] buffer = new byte[1024];

    try{
        InputStream in = channel.getInputStream();
        String line = "";
        while (true){
            while (in.available() > 0) {
                int i = in.read(buffer, 0, 1024);
                if (i < 0) {
                    break;
                }
                line = new String(buffer, 0, i);
                System.out.println(line);
            }

            if(line.contains("logout")){
                break;
            }

            if (channel.isClosed()){
                break;
            }
            try {
                Thread.sleep(1000);
            } catch (Exception ee){}
        }
    }catch(Exception e){
        System.out.println("Error while reading channel output: "+ e);
    }

}

public static void close(){
    channel.disconnect();
    session.disconnect();
    System.out.println("Disconnected channel and session");
}


public static void main(String[] args){
    List<String> commands = new ArrayList<String>();
    commands.add("ls -l");

    executeCommands(commands);
    close();
}
}

This solution is also useful if you need to send multiple commands at a time and keep the channel open to reuse it later.

如果您需要一次发送多个命令并保持通道打开以供以后重用,此解决方案也很有用。

回答by gdbj

Taking the example provided by Mihail, other info on the internets, and the feedback from Martin, here's a reworked solution using exec. Note that opening a session allows multiple commands to be sent, each one opening it's own channel for input/output.

以 Mihail 提供的示例、互联网上的其他信息以及 Martin 的反馈为例,这是一个使用exec. 请注意,打开会话允许发送多个命令,每个命令都打开自己的输入/输出通道。

Rant:I really dislike having to get the process' OUTPUTstream to write to. What an annoying paradigm (at least for me). What I wanted is the processes input stream to write my output to, and had an amazingly difficult time working out that it's inverted. Is it just me or does the following (pseudocode) not make way more sense??

咆哮:我真的不喜欢必须让进程的OUTPUT流写入。多么烦人的范式(至少对我而言)。我想要的是将我的输出写入的进程输入流,并且发现它被反转的过程非常困难。是我还是以下(伪代码)没有更有意义?

channel.getInputStream().write("here's some text to write into my channel.");

channel.getInputStream().write("here's some text to write into my channel.");

String ret = channel.getOutputStream().getOutput();

String ret = channel.getOutputStream().getOutput();

Anyways, thanks to Mihail and Martin for their comments / input.

无论如何,感谢 Mihail 和 Martin 的评论/意见。

public class SSHConnectionManager {

    private Session session;

    private String username = "user";
    private String password = "password";
    private String hostname = "myhost";

    public SSHConnectionManager() { }

    public SSHConnectionManager(String hostname, String username, String password) {
        this.hostname = hostname;
        this.username = username;
        this.password = password;
    }

    public void open() throws JSchException {
        open(this.hostname, this.username, this.password);
    }

    public void open(String hostname, String username, String password) throws JSchException{

        JSch jSch = new JSch();

        session = jSch.getSession(username, hostname, 22);
        Properties config = new Properties(); 
        config.put("StrictHostKeyChecking", "no");  // not recommended
        session.setConfig(config);
        session.setPassword(password);

        System.out.println("Connecting SSH to " + hostname + " - Please wait for few seconds... ");
        session.connect();
        System.out.println("Connected!");
    }

    public String runCommand(String command) throws JSchException, IOException {

        String ret = "";

        if (!session.isConnected())
            throw new RuntimeException("Not connected to an open session.  Call open() first!");

        ChannelExec channel = null;
        channel = (ChannelExec) session.openChannel("exec");

        channel.setCommand(command);
        channel.setInputStream(null);

        PrintStream out = new PrintStream(channel.getOutputStream());
        InputStream in = channel.getInputStream(); // channel.getInputStream();

        channel.connect();

        // you can also send input to your running process like so:
        // String someInputToProcess = "something";
        // out.println(someInputToProcess);
        // out.flush();

        ret = getChannelOutput(channel, in);

        channel.disconnect();

        System.out.println("Finished sending commands!");

        return ret;
    }


    private String getChannelOutput(Channel channel, InputStream in) throws IOException{

        byte[] buffer = new byte[1024];
        StringBuilder strBuilder = new StringBuilder();

        String line = "";
        while (true){
            while (in.available() > 0) {
                int i = in.read(buffer, 0, 1024);
                if (i < 0) {
                    break;
                }
                strBuilder.append(new String(buffer, 0, i));
                System.out.println(line);
            }

            if(line.contains("logout")){
                break;
            }

            if (channel.isClosed()){
                break;
            }
            try {
                Thread.sleep(1000);
            } catch (Exception ee){}
        }

        return strBuilder.toString();   
    }

    public void close(){        
        session.disconnect();
        System.out.println("Disconnected channel and session");
    }


    public static void main(String[] args){

        SSHConnectionManager ssh = new SSHConnectionManager();
        try {
            ssh.open();
            String ret = ssh.runCommand("ls -l");

            System.out.println(ret);
            ssh.close();

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}