从Java通过SSH执行Bash命令时出现问题

我无法通过SSH从Java在远程GNU / Linux系统上执行命令。 在本地Bash中执行时,以下命令可以正常工作(当然用户和主机不同但行为不变)。

$ ssh user@host.example.com 'hostname' host $ ssh user@host.example.com 'hostname -f' host.example.com $ ssh user@host.example.com "hostname -f" host.example.com 

在没有参数的情况下,执行我认为与Java相同的任何事情都会失败。

 import java.io.ByteArrayOutputStream; import java.io.IOException; import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.DefaultExecutor; import org.apache.commons.exec.Executor; import org.apache.commons.exec.PumpStreamHandler; public class SOPlayground { public static void main(String[] args) throws Exception { for (String argument : new String[]{"hostname", "'hostname'", "\"hostname\"", "'hostname -f'", "\"hostname -f\""}) { CommandLine commandLine = new CommandLine("ssh"); commandLine.addArgument("user@host.example.com"); commandLine.addArgument(argument); System.out.println(commandLine); final Executor executor = new DefaultExecutor(); try (ByteArrayOutputStream os = new ByteArrayOutputStream(); ByteArrayOutputStream err = new ByteArrayOutputStream()) { executor.setStreamHandler(new PumpStreamHandler(os, err)); int exitcode = executor.execute(commandLine); System.out.println("exitcode=" + exitcode); System.out.println(new String(os.toByteArray(), "UTF-8")); System.err.println(new String(err.toByteArray(), "UTF-8")); } catch (IOException ex) { System.err.println(ex.getMessage()); } } } } 

输出是:

 ssh user@host.example.com hostname exitcode=0 host ssh user@host.example.com 'hostname' exitcode=0 host ssh user@host.example.com "hostname" exitcode=0 host ssh user@host.example.com 'hostname -f' Process exited with an error: 127 (Exit value: 127) ssh user@host.example.com "hostname -f" Process exited with an error: 127 (Exit value: 127) 

如您所见,通过SSH从Java执行hostname -f失败,退出代码为127.我想知道 bash(本地或远程)无法找到什么命令。

我试过用这个变种

 addArgument(String argument, boolean handleQuoting) 

但结果没有差别。

我如何从通过SSH工作的Java构建CommandLine

您可以将JSch与publickey身份validation一起使用。

如果您只想使用exec执行单个远程命令然后关闭连接,那么您有一个工作示例:

 public static void main(String[] args) { String user = "--"; String host = "--"; try { JSch jsch = new JSch(); // key authentication jsch.addIdentity("id_rsa"); // open a new session on port 22 Session session = jsch.getSession(user, host, 22); session.setConfig("StrictHostKeyChecking", "no"); session.connect(); String command = "ls /"; Channel channel = session.openChannel("exec"); ((ChannelExec) channel).setCommand(command); channel.setInputStream(null); ((ChannelExec) channel).setErrStream(System.err); InputStream in = channel.getInputStream(); channel.connect(); StringBuilder sb = new StringBuilder(); byte[] tmp = new byte[1024]; while (true) { while (in.available() > 0) { int i = in.read(tmp, 0, 1024); if (i < 0) break; sb.append(new String(tmp, 0, i)); } if (channel.isClosed()) { if (in.available() > 0) continue; System.out.println("exit-status: " + channel.getExitStatus()); break; } try { Thread.sleep(500); } catch (Exception ee) { } } //disconnecting and closing channel.disconnect(); session.disconnect(); System.out.println("Output: "); System.out.println(sb.toString()); } catch (Exception e) { //something should be done here e.printStackTrace(); } } 

输出:

 exit-status: 0 Output: 1 bin boot cgroup dev etc home lib lib64 lost+found .... 

希望能帮助到你

注意: id_rsa是密钥文件的路径

感谢关于Jsch的答案。 我尝试了一种不同的方法,将命令写入临时文件,然后在本地执行。

 import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.DefaultExecutor; import org.apache.commons.exec.Executor; import org.apache.commons.exec.PumpStreamHandler; import org.apache.commons.io.IOUtils; public class SOPlayground { public static void main(String[] args) throws Exception { final String command = "ssh user@host 'hostname -f'"; int exitCode = executeCommand(command); } private static int executeCommand(final String command) { int exitcode = -1; File temp = null; try { temp = File.createTempFile("foo", ".tmp"); try (OutputStream os = new FileOutputStream(temp);) { IOUtils.write(command, os); } finally { // os is closed } CommandLine commandLine = new CommandLine("bash"); commandLine.addArgument(temp.getAbsolutePath()); final Executor executor = new DefaultExecutor(); try (ByteArrayOutputStream os = new ByteArrayOutputStream(); ByteArrayOutputStream err = new ByteArrayOutputStream()) { executor.setStreamHandler(new PumpStreamHandler(os, err)); exitcode = executor.execute(commandLine); System.out.println("exitcode=" + exitcode); System.out.println(new String(os.toByteArray(), "UTF-8")); System.err.println(new String(err.toByteArray(), "UTF-8")); } finally { // os and err are closed } } catch (IOException ex) { System.err.println(ex.getMessage); } finally { if (temp != null) { temp.delete(); } } return exitcode; } }