JSch is an excellent library for supporting remote connections over ssh, including the execution of remote commands (or shell scripts).
There are numerous examples of how to use JSch at JSch Examples, but pay particular attention to Exec.
At its base, what one does is:
- Obtain credentials
- Create a
Session - Open a
Channelwithin theSession - Deal with streams as desired
While typing, the OP also posted an additional question and an example. The example from http://www.codesandscripts.com/2014/10/java-program-to-execute-shell-scripts-on-remote-server.html seems fine as well.
As to the pushing the script to the server, start by using either scp or sftp (the latter we've found to be more reliable) to move the file to the remote machine, be sure to send an exec of chmod u+x, and then invoke the script.
JSch is an excellent library for supporting remote connections over ssh, including the execution of remote commands (or shell scripts).
There are numerous examples of how to use JSch at JSch Examples, but pay particular attention to Exec.
At its base, what one does is:
- Obtain credentials
- Create a
Session - Open a
Channelwithin theSession - Deal with streams as desired
While typing, the OP also posted an additional question and an example. The example from http://www.codesandscripts.com/2014/10/java-program-to-execute-shell-scripts-on-remote-server.html seems fine as well.
As to the pushing the script to the server, start by using either scp or sftp (the latter we've found to be more reliable) to move the file to the remote machine, be sure to send an exec of chmod u+x, and then invoke the script.
Here is a JSch example to SSH login (password) a remote server and runs a shell script.
package com.mkyong.io.howto;
import com.jcraft.jsch.*;
import java.io.IOException;
import java.io.InputStream;
public class RunRemoteScript {
private static final String REMOTE_HOST = "1.1.1.1";
private static final String USERNAME = "";
private static final String PASSWORD = "";
private static final int REMOTE_PORT = 22;
private static final int SESSION_TIMEOUT = 10000;
private static final int CHANNEL_TIMEOUT = 5000;
public static void main(String[] args) {
String remoteShellScript = "/root/hello.sh";
Session jschSession = null;
try {
JSch jsch = new JSch();
jsch.setKnownHosts("/home/mkyong/.ssh/known_hosts");
jschSession = jsch.getSession(USERNAME, REMOTE_HOST, REMOTE_PORT);
// not recommend, uses jsch.setKnownHosts
//jschSession.setConfig("StrictHostKeyChecking", "no");
// authenticate using password
jschSession.setPassword(PASSWORD);
// 10 seconds timeout session
jschSession.connect(SESSION_TIMEOUT);
ChannelExec channelExec = (ChannelExec) jschSession.openChannel("exec");
// run a shell script
channelExec.setCommand("sh " + remoteShellScript + " mkyong");
// display errors to System.err
channelExec.setErrStream(System.err);
InputStream in = channelExec.getInputStream();
// 5 seconds timeout channel
channelExec.connect(CHANNEL_TIMEOUT);
// read the result from remote server
byte[] tmp = new byte[1024];
while (true) {
while (in.available() > 0) {
int i = in.read(tmp, 0, 1024);
if (i < 0) break;
System.out.print(new String(tmp, 0, i));
}
if (channelExec.isClosed()) {
if (in.available() > 0) continue;
System.out.println("exit-status: "
+ channelExec.getExitStatus());
break;
}
try {
Thread.sleep(1000);
} catch (Exception ee) {
}
}
channelExec.disconnect();
} catch (JSchException | IOException e) {
e.printStackTrace();
} finally {
if (jschSession != null) {
jschSession.disconnect();
}
}
}
}
Refer to this example How to run a remote shell script in Java
Executing Shell Scripts from Java Program by ssh to remote server - Stack Overflow
Execute the shell script present in remote server using java - Stack Overflow
bash - Any possibility to execute shell script from java file? - Unix & Linux Stack Exchange
How to call Linux shell scripts from java remotely - Programming & Development - Spiceworks Community
Videos
You can execute the scripts without even copying them to remote server. Invoke a bash shell and pipe the commands from shell script to the remote process ( bash in this case ).
So, here is a simple script echo "Hi there!"; env. Now we can run this script like this:
$ echo 'echo "Hi there!"; env' | ssh localhost bash
tuxdna@localhost's password:
Hi there!
XDG_SESSION_ID=10
SHELL=/bin/bash
SSH_CLIENT=127.0.0.1 43064 22
USER=tuxdna
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
MAIL=/var/mail/tuxdna
PWD=/home/tuxdna
LANG=en_IN
HOME=/home/tuxdna
SHLVL=2
LANGUAGE=en_IN:en
LOGNAME=tuxdna
SSH_CONNECTION=127.0.0.1 43064 127.0.0.1 22
XDG_RUNTIME_DIR=/run/user/1000
_=/usr/bin/env
Essentially you have to write the shell script to STDIN of the remote process.
Yes, but probably not in the way you are thinking.
You need to copy the script over to the remote system.
Check out http://seancode.blogspot.com.au/2008/02/jsch-scp-file-in-java.html who's written a FileSender wrapper that might help
You could also check out Copying a file in sftp with jsch library just out of interest
You could also check out the included examples http://www.jcraft.com/jsch/examples/ (knew they were there somewhere)
I don't know anything about Java, but I can show you a proof of concept. Say we have localfile.txt:
Here is the local file.
and on the remote machine, we have remote.sh:
#!/bin/bash
cat /dev/stdin
Note that the script on the remote machine invokes a program which reads from stdin. Then pass the contents of localfile.txt to your ssh command:
user@local:~$ cat localfile.txt | ssh user@remote remote.sh
Here is the local file.
Your Java program is trying to read a file which does not exist on the remote machine. I guess you could try to mimic a local file.
Change remote.sh to:
#!/bin/bash
cat "$@"
and invoke it with
user@local:~$ cat localfile.txt | ssh user@remote 'remote.sh <(cat /dev/stdin)'
Here is the local file.
I think it would be easier to change that part in your Java program to read from stdin.
I guess things might get messy if localfile.txt contains anything that might be interpreted by the shell as expandable (such as *), but that's for you to figure out.
The problem is that the shell redirection (<) sends the file over the ssh tunnel. And the Java class is expecting not the file, but a string with the "filename" of a local file that will be read with a FileReader.
Instead of passing the filename to the FileReader, read from the standard input.
InputStreamReader isReader = new InputStreamReader(System.in);
BufferedReader iR = new BufferedReader (isReader);
Used this as a reference: https://stackoverflow.com/questions/5724646/how-to-pipe-input-to-java-program-with-bash
Now your class will be:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.OutputStreamWriter;
import java.io.InputStreamReader;
public class ReadFirstLine
{
public static void main(String[] args) throws Exception
{
String filename = args[0];
System.out.println(filename);
//BufferedReader iR = new BufferedReader (new FileReader(filename));
InputStreamReader isReader = new InputStreamReader(System.in);
BufferedReader iR = new BufferedReader (isReader);
BufferedWriter oW = new BufferedWriter(new OutputStreamWriter(System.out));
//outputWriter.write(iR.readLine());
System.out.println(iR.readLine());
iR.close();
oW.close();
}
}
But for this task I would definitely use instead:
head -1 filename.txt
:)
Basically, I don't think you can do that, the way you are trying. The Runtime.exec(...) will delegate to the OS to perform the actual execution.
There are any number of ways to achieve what you want, either purely in Java or via additional utilities based on the OS.
You could SSH or telnet to the remote machine and execute the commands via those interfaces.
You could write a client server app, where the server would allow you to send commands to it to be executed on your behalf (but you must understand that this is a massive security risk).
Check out Jsch or Ganymed SSH. I have used the latter to perform ssh/scp tasks programmatically.