当前位置: 首页 > 知识库问答 >
问题:

JSch 命令行管理程序通道在继续之前逐个执行命令测试结果

秦安怡
2023-03-14

我有一个连接到SSH外壳的程序。我能够执行命令并从中读取输出。

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

我用过这个问题的程序:JSch问题-无法检索完整的命令输出

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”通道而不是“exec”,因为服务器不允许“exec”通道:链接

共有1个答案

齐鹏程
2023-03-14

一般来说,您应该为此使用“执行”通道。“外壳”通道不应用于自动执行命令。

但是我知道你的服务器不支持“exec”频道。我为其他读者添加了上面的评论,不要试图使用这个解决方案,除非他们真的必须这样做。

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

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

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

然后你继续阅读输出,直到你找到一行开头的“命令已经完成代码-”。分析退出代码并决定如何继续。

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

旁注:

  • “#!/bin/bash”纯属无稽之谈。shell忽略所有以#开头的命令(它是注释)。发送它没有意义
  • 不要使用StrictHostKeyChecking=no。请参阅会话的JSch SFTP安全性。setConfig(“StrictHostKeyChecking”,“no”)
 类似资料:
  • 我试图在unix中使用JSCHSSH类(com.jcraft.jsch)执行一些工具。我的工具有一个选择菜单。我需要转到工具所在的文件夹,执行它并选择请求的选项。在每个命令之后,(cd,execute,…)我希望检查输出并检查状态代码(0/1)。我有下面的代码按预期执行它,但在这段代码中,我找不到一种方法来检查每个命令后的输出。 我无法找到一种方法,但我怎么能分开的命令,并打印他们一个接一个(在同

  • 为什么/我的目标: 我有一个由pi组成的小型网状网络,每天大部分时间都在运行脚本。我想取消停机时间,但是代码有时会在连续循环3-4天后停止工作,(有时长达一周,代码才会出现错误并停止)。 每个节点上运行的脚本用“最后签入”字段更新mySQL数据库。 我希望用Java编写一个小型后台程序,它将在我的服务器上无限期运行,时不时地检查每个站点的“最后签入”,如果它注意到一个节点宕机,远程ssh进入该节点

  • 我有一个带有两个按钮的swing应用程序,用于运行和停止执行JSch命令。所以我有下一个方法,当我们点击开始按钮时调用: 正如你上面看到的,我们有is取消变量,它是布尔变量,当点击停止按钮时,我们将其设置为false。所以我的问题是当用户点击停止按钮和通道与会话成为断开,zgrep表达式继续工作在服务器上。我认为channel.disconnect()应该停止我在服务器上运行的所有命令,有人能建议

  • 问题内容: 我想知道是否有一种方法可以在Go中运行一定的时间,然后在从通道接收到值后将其杀死。在似乎不支持命令管道。谢谢。 问题答案: 这是我的管道示例,通过OS Std Pipe归档一个调用文件b,您可以对其进行编辑并添加计时器以执行所需的操作。 文件b:

  • 问题内容: 我想在我运行的每个bash命令之后打印日期。 这可以帮助我了解远离键盘时要执行多少命令。 我知道我能做 获取日期,但我不知道在bash上执行的每个命令之后如何甚至是否可以运行此命令。 我也会对在每个命令 之前 运行同一命令感兴趣,因此我可以知道一个命令花费了多长时间。 可能吗? 我应该编辑什么文件? 例如: 如果我也可以介绍以下功能,我将很高兴: 第一个日期是我运行程序的日期,第二个是