在sshj中执行命令序列

我需要使用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列表。

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

  • Expect4J
  • ExpectJ
  • 预计换的Java

但是,当我即将解决类似的问题时,我发现这些库相当陈旧。 它们还引入了许多不需要的依赖项。 所以我创建了自己的,并为其他人提供了它。 它被称为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(); } 

这是完整可行示例的链接。

虽然很奇怪,但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; ; ");

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

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

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

 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; }