I was trying to execute multiple commands through SSH protocol using the JSch library. But I seem to have stuck and cannot find any solution. The setCommand()
m
The command is a String and can be anything the remote shell accepts. Try
cmd1 ; cmd2 ; cmd3
to run several commands in sequence. Or
cmd1 && cmd2 && cmd3
to run commands until one fails.
Even this might work:
cmd1
cmd2
cmd3
or in Java:
channel.setCommand("cmd1\ncmd2\ncmd3");
Sidenote: Don't put passwords and user names into the code. Put them into a property file and use a system property to specify the name of the property file. That way, you can keep the file even outside the project and make sure passwords/user names don't leak.
If you do not have to distinguish the inputs or outputs of the individual commands, the answer from Aaron (giving all the commands in a row, separated by \n
or ;
) is fine.
If you have to handle them separately, or don't know the later commands before the earlier ones are finished: You can open multiple exec-Channels on the same Session (i.e. connection), one after the other (i.e. after the one before was closed). Each one has its own command. (But they don't share environment, so a cd
command in the first one has no effect on later ones.)
You simply have to take care to have the Session object around, and not create a new one for each command.
Another option would be a shell channel, and then passing the individual commands to the remote shell as input (i.e. via a stream). But then you have to take care to not mix the the input to one command with the next command (i.e. this works only if you know what the commands are doing, or if you have an interactive user who can supply both input to the command and the next command, and knows which one is to be used when.)
Avoid using "shell" channel as much as possible. The "shell" channel is intended to implement an interactive session, not to automate a command execution. With "shell" channel, you will face many unwanted side effects.
To automate a command execution, use "exec" channel.
Usually, you can open as many "exec" channels as you need, using each to execute one of your commands. You can open the channels in sequence or even in parallel.
For a complete example of "exec" channel use, see JSch Exec.java example.
This way each command executes in an isolated environment. What may be an advantage, but it can also be undesirable in some cases.
If you need to execute commands in a way that previous commands affect later commands (like changing a working directory or setting an environment variable), you have to execute all commands in the same channel. Use an appropriate construct of the server's shell for that. On most systems you can use semicolons:
execChannel.setCommand("command1 ; command2 ; command3");
On *nix servers, you can also use &&
to make the following commands be executed only when the previous commands succeeded:
execChannel.setCommand("command1 && command2 && command3");
See also Execute a list of commands from an ArrayList using JSch exec in Java.
Most complicated situation is, when the commands depend on one another and you need to process results of previous commands before proceeding to other commands.
When you have such need, it usually indicates a bad design. Think hard, if this is really the only solution to your problem. Or consider implementing a server-side shell script to implement the logic, instead of doing it remotely from Java code. Shell scripts have much more powerful techniques to check for results of previous commands, then you have with SSH interface in JSch.
Anyway, see JSch Shell channel execute commands one by one testing result before proceeding.
Side note: Do not use StrictHostKeyChecking=no
. See JSch SFTP security with session.setConfig("StrictHostKeyChecking", "no");.
Setup an SCPInfo object to hold the username, password, port:22 and ip.
List<String> commands = new ArrayList<String>();
commands.add("touch test1.txt");
commands.add("touch test2.txt");
commands.add("touch test3.txt");
runCommands(scpInfo, commands);
public static void runCommands(SCPInfo scpInfo, List<String> commands){
try {
JSch jsch = new JSch();
Session session = jsch.getSession(scpInfo.getUsername(), scpInfo.getIP(), scpInfo.getPort());
session.setPassword(scpInfo.getPassword());
setUpHostKey(session);
session.connect();
Channel channel=session.openChannel("shell");//only shell
channel.setOutputStream(System.out);
PrintStream shellStream = new PrintStream(channel.getOutputStream()); // printStream for convenience
channel.connect();
for(String command: commands) {
shellStream.println(command);
shellStream.flush();
}
Thread.sleep(5000);
channel.disconnect();
session.disconnect();
} catch (Exception e) {
System.err.println("ERROR: Connecting via shell to "+scpInfo.getIP());
e.printStackTrace();
}
}
private static void setUpHostKey(Session session) {
// Note: There are two options to connect
// 1: Set StrictHostKeyChecking to no
// Create a Properties Object
// Set StrictHostKeyChecking to no
// session.setConfig(config);
// 2: Use the KnownHosts File
// Manually ssh into the appropriate machines via unix
// Go into the .ssh\known_hosts file and grab the entries for the hosts
// Add the entries to a known_hosts file
// jsch.setKnownHosts(khfile);
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
}