【问题标题】:execute sequense of commands in sshj在 ssh 中执行命令序列
【发布时间】:2014-05-08 13:07:32
【问题描述】:

我需要使用 sshj 库通过 ssh 在远程服务器上执行一些命令序列。

我愿意

        Session session = ssh.startSession();
        Session.Command cmd = session.exec("ls -l");
        System.out.println(IOUtils.readFully(cmd.getInputStream()).toString());
        cmd.join(10, TimeUnit.SECONDS);
        Session.Command cmd2 = session.exec("ls -a");
        System.out.println(IOUtils.readFully(cmd2.getInputStream()).toString());

它把我扔了

net.schmizz.sshj.common.SSHRuntimeException: 这个会话通道是 都用完了

但是我不能为每一个命令重新创建会话,因为这个例子会显示主目录列表,而不是 /some/dir 列表。

【问题讨论】:

  • 可能你需要在执行下一个命令之前从cmd.getInputStream()读取数据...

标签: java ssh sshj


【解决方案1】:

尽管很奇怪,session 只能使用一次。因此,您必须每次都重置会话。

    Session session = ssh.startSession();
    Session.Command cmd = session.exec("ls -l");
    System.out.println(IOUtils.readFully(cmd.getInputStream()).toString());
    cmd.join(10, TimeUnit.SECONDS);

    session = ssh.startSession();
    Session.Command cmd2 = session.exec("ls -a");
    System.out.println(IOUtils.readFully(cmd2.getInputStream()).toString());

或者,如果您要连接的 shell 支持分隔命令(并且情况允许),您可以这样做(bash 示例):

session.exec("ls -l; <command 2>; <command 3>");

【讨论】:

  • startSession() 是否重新连接到服务器?只是为了确保我没有敲击服务器
【解决方案2】:

您可以考虑使用Expect-like 第三方库,它可以简化远程服务的使用和捕获输出。这些库旨在执行一系列命令。您可以尝试以下一组不错的选项:

然而,当我要解决类似的问题时,我发现这些库已经相当老了。它们还引入了许多不需要的依赖项。所以我创建了自己的,并提供给其他人。它被称为ExpectIt。我的图书馆的优点在项目主页上都有说明。你可以试试看。

这是一个使用 sshj 与公共远程 SSH 服务交互的示例:

    SSHClient ssh = new SSHClient();
    ...
    ssh.connect("sdf.org");
    ssh.authPassword("new", "");
    Session session = ssh.startSession();
    session.allocateDefaultPTY();
    Shell shell = session.startShell();
    Expect expect = new ExpectBuilder()
            .withOutput(shell.getOutputStream())
            .withInputs(shell.getInputStream(), shell.getErrorStream())
            .build();
    try {
        expect.expect(contains("[RETURN]"));
        expect.sendLine();
        String ipAddress = expect.expect(regexp("Trying (.*)\\.\\.\\.")).group(1);
        System.out.println("Captured IP: " + ipAddress);
        expect.expect(contains("login:"));
        expect.sendLine("new");
        expect.expect(contains("(Y/N)"));
        expect.send("N");
        expect.expect(regexp(": $"));
        expect.send("\b");
        expect.expect(regexp("\\(y\\/n\\)"));
        expect.sendLine("y");
        expect.expect(contains("Would you like to sign the guestbook?"));
        expect.send("n");
        expect.expect(contains("[RETURN]"));
        expect.sendLine();
    } finally {
        session.close();
        ssh.close();
        expect.close();
    }

这里是完整可行的example的链接。

【讨论】:

    【解决方案3】:

    这个问题很老,但只是为了澄清,引用维基https://github.com/hierynomus/sshj/wiki

    会话对象不可重用,因此您只能通过 exec()、startShell() 或 startSubsystem() 分别拥有一个命令/shell/子系统。但是您可以通过单个连接启动多个会话。

    在我们的例子中,我们已经把它放在一个函数中

    public String runCmd(SSHClient sshClient, String command) throws IOException  {
        String response = "";
    
        try (Session session = sshClient.startSession()) {
            final Command cmd = session.exec(command);
            response = (IOUtils.readFully(cmd.getInputStream()).toString());
            cmd.join(5, TimeUnit.SECONDS);
            // System.out.println("\n** exit status: " + cmd.getExitStatus());
        } 
        return response;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-10
      • 1970-01-01
      • 2022-09-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多