我在使用Java通过SSH在远程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
在没有参数的情况下执行比hostname
更复杂的事情,我认为从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从SSH执行hostname -f
失败,退出代码为127.我想知道什么 bash(本地或远程)无法找到什么命令。
我试图使用变体
addArgument(String argument, boolean handleQuoting)
但结果没有差异。
我如何从通过SSH工作的Java构建CommandLine
?
答案 0 :(得分:2)
您可以将JSch与publickey身份验证一起使用。
如果您只想使用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
是密钥文件的路径
答案 1 :(得分:0)
感谢有关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;
}
}