java - JSch Shell channel 执行命令一一测试结果再继续

标签 java ssh jsch

我有一个用于连接 SSH shell 的程序。我能够执行命令并读取它们的输出。

但我有一个新要求。现在我需要执行一个命令并读取输出(如果成功执行下一个命令)。

我使用了这个问题中的程序:JSch issue - Cannot retrieve full command output

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.setPty(false);
                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();
    }
}

我需要使用“shell” channel 而不是“exec”,因为服务器不允许“exec” channel :link

最佳答案

一般来说,您应该为此使用“exec” channel 。 “shell” channel 不应用于自动执行命令。

但我了解到您的服务器不支持“exec” channel 。 我为其他读者添加了上述评论,不要尝试使用此解决方案,除非他们确实必须这样做。

<小时/>

正如 @Yair Harel 已经评论过的,如果你必须使用“shell” channel ,你就必须使用 shell 技术。

因此,在您的特定情况下,您可能希望远程 shell 在命令完成后打印一些唯一的字符串和退出代码:

out.println(command + " ; echo Command-has-finished-with-code-$?");

然后继续阅读输出,直到找到以 “Command-has-finished-with-code-” 开头的行。您解析退出代码并决定如何继续。

请注意,命令语法(特别是命令分隔符 ; 和退出代码变量 $?)是特定于操作系统和 shell 的。由于您的服务器不是标准类型,因此语法可能会有所不同。

<小时/>

旁注:

关于java - JSch Shell channel 执行命令一一测试结果再继续,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35533825/

相关文章:

java - 下载后 JSch 正在从服务器删除文件

java - jsch ssh 连接无法获取authorized_keys

java - 将 Single 应用于 ObservableSource 并且不要过度读取

java - Symfony JAVA_HOME 未设置

java - 尝试资源

ssh - 期望脚本运行 Ansible playbook

java - JSch channel.disconnect 阻止打印日志

java - 如何在我变暗的图层上方显示一个 block

linux - 如何安装git lfs

java - 使用来自 ChannelSftp.get 的输入流时 ChannelSftp.put 方法卡住