Java IO Tutorial

Java – Run shell script on a remote server

This article shows how to use JSch library to run or execute a shell script in a remote server via SSH.

pom.xml

  <dependency>
      <groupId>com.jcraft</groupId>
      <artifactId>jsch</artifactId>
      <version>0.1.55</version>
  </dependency>

1. Run Remote Shell Script

This Java example uses JSch to SSH login a remote server (using password), and runs a shell script hello.sh.

1.1 Here is a simple shell script in a remote server, IP address is 1.1.1.1.

hello.sh

#! /bin/sh
echo "hello $1\n";

Assigned the execute permission.

Terminal

$ chmod +x hello.sh

1.2 In local, we can use the below code to run or execute the above shell script in a remote server.

RunRemoteScript.java

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();
            }
        }

    }
}

Output

Terminal

hello mkyong

exit-status: 0

Note
For JSch UnknownHostKey exception, please add the remote server ip into the .ssh/known_hosts, read this.

2. Run Remote Command

2.1 The below example is very similar to the above example#1. Instead, it uses a private key id_rsa to SSH login a remote server, makes sure the remote server configured the public key correctly.


  jsch.addIdentity("/home/mkyong/.ssh/id_rsa");

2.2 And we changed the command to ls, the rest of the codes are the same.


  channelExec.setCommand("ls -lsah");

2.3 This Java example runs a remote server command ls -lsah to display the directory listing.

RunRemoteCommand.java

package com.mkyong.io.howto;

import com.jcraft.jsch.*;

import java.io.IOException;
import java.io.InputStream;

public class RunRemoteCommand {

    private static final String REMOTE_HOST = "1.1.1.1";
    private static final String USERNAME = "";
    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) {

        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 private key
            jsch.addIdentity("/home/mkyong/.ssh/id_rsa");

            // 10 seconds timeout session
            jschSession.connect(SESSION_TIMEOUT);

            ChannelExec channelExec = (ChannelExec) jschSession.openChannel("exec");

            // Run a command
            channelExec.setCommand("ls -lsah");

            // 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();
            }
        }

    }
}

Output

Terminal

otal 48K
4.0K drwx------  6 root root 4.0K Aug  4 07:57 .
4.0K drwxr-xr-x 22 root root 4.0K Sep 11  2019 ..
8.0K -rw-------  1 root root 5.5K Aug  3 08:50 .bash_history
4.0K -rw-r--r--  1 root root  570 Jan 31  2010 .bashrc
4.0K drwx------  2 root root 4.0K Dec 15  2019 .cache
4.0K drwx------  2 root root 4.0K Dec 15  2019 .docker
4.0K -rwxr-xr-x  1 root root   31 Aug  4 07:54 hello.sh
4.0K -rw-r--r--  1 root root  148 Aug 17  2015 .profile
4.0K drwx------  2 root root 4.0K Aug  3 05:32 .ssh
4.0K drwxr-xr-x  2 root root 4.0K Aug  3 04:42 test
4.0K -rw-------  1 root root 1.2K Aug  4 07:57 .viminfo
exit-status: 0

2.4 Now, we test an invalid command abc

RunRemoteCommand.java

  // Run a invalid command
  channelExec.setCommand("abc");

Output

Terminal

bash: abc: command not found
exit-status: 127

The errors will output to the System.err.

Download Source Code

$ git clone https://github.com/mkyong/core-java

$ cd java-io

References

About Author

author image
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter. If you like my tutorials, consider make a donation to these charities.

Comments

Subscribe
Notify of
1 Comment
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Avinash Pande
2 years ago

Thanks mkyong!! your, some portion of solution works for me & I am able to run the shell scripts which is placed on AWS EMR Cluster. After spending almost 6-8 hours.

Last edited 2 years ago by Avinash Pande