I am having trouble executing commands on a remote GNU/Linux system over SSH from Java. The following commands work fine when executed in the local Bash (of course the user and host are different but the behaviour is unchanged).
$ 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
Doing what I think is the same from Java fails for anything more complex than hostname
without arguments.
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());
}
}
}
}
The output is:
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)
As you can see, executing hostname -f
over SSH from Java fails with an exit code of 127. I wonder what bash (local or remote) was unable to find what command.
I've tried to use the variant
addArgument(String argument, boolean handleQuoting)
but there was no difference in the result.
How must I build a CommandLine
from Java that works over SSH?
Thanks for the answer regarding Jsch. I've tried a different approach which writes the command to a temporary file and then executes it locally.
You can use JSch with publickey authentication.
If you only want to use
exec
to execute a single remote command and then closes the connection, here you have a working example:Output:
Hope it helps
Note:
id_rsa
is the path to the key file