If you want to execute shell scripts on remote server and get output with the help of your java program then you are at right place. In this tutorial we will be using Java secure channel ( Jsch ) to log on to remote server, execute the shell script and capture the output. JSch is a pure Java implementation of SSH2. ( download jSch ).
We will be using this library for our program. Download the jar and add to your build path. Once you have added it to your build path you will be able to make secure connections to server. It requires java version 1.4 or greater. I would highly recommend to go through the requirements for this library on their official website ( http://www.jcraft.com/jsch/ ).
We will be using this library for our program. Download the jar and add to your build path. Once you have added it to your build path you will be able to make secure connections to server. It requires java version 1.4 or greater. I would highly recommend to go through the requirements for this library on their official website ( http://www.jcraft.com/jsch/ ).
Program :
package service; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.JSch; import com.jcraft.jsch.Session; /** * This class executes the shell script on the remote server * Requires the jSch java library * @author Saket kumar * */ public class ShellExecuter{ private static String USERNAME ="root"; // username for remote host private static String PASSWORD ="password"; // password of the remote host private static String host = "113.33.111.111"; // remote host address private static int port=22; /** * This method will execute the script file on the server. * This takes file name to be executed as an argument * The result will be returned in the form of the list * @param scriptFileName * @return */ public List<string> executeFile(String scriptFileName) { List<string> result = new ArrayList<string>(); try { /** * Create a new Jsch object * This object will execute shell commands or scripts on server */ JSch jsch = new JSch(); /* * Open a new session, with your username, host and port * Set the password and call connect. * session.connect() opens a new connection to remote SSH server. * Once the connection is established, you can initiate a new channel. * this channel is needed to connect to remotely execution program */ Session session = jsch.getSession(USERNAME, host, port); session.setConfig("StrictHostKeyChecking", "no"); session.setPassword(PASSWORD); session.connect(); //create the excution channel over the session ChannelExec channelExec = (ChannelExec)session.openChannel("exec"); // Gets an InputStream for this channel. All data arriving in as messages from the remote side can be read from this stream. InputStream in = channelExec.getInputStream(); // Set the command that you want to execute // In our case its the remote shell script channelExec.setCommand("sh "+scriptFileName); // Execute the command channelExec.connect(); // Read the output from the input stream we set above BufferedReader reader = new BufferedReader(new InputStreamReader(in)); String line; //Read each line from the buffered reader and add it to result list // You can also simple print the result here while ((line = reader.readLine()) != null) { result.add(line); } //retrieve the exit status of the remote command corresponding to this channel int exitStatus = channelExec.getExitStatus(); //Safely disconnect channel and disconnect session. If not done then it may cause resource leak channelExec.disconnect(); session.disconnect(); if(exitStatus < 0){ // System.out.println("Done, but exit status not set!"); } else if(exitStatus > 0){ // System.out.println("Done, but with error!"); } else{ // System.out.println("Done!"); } } catch(Exception e) { System.err.println("Error: " + e); } return result; } }
how set password , if any command required password
ReplyDeleteyou can use session.setPassword method, as provided in above program at line number 40
DeleteHow to pass arguments to shell script?
DeleteSame as you use to do it normally on terminal,
Deleteex : channelExec.setCommand("sh "+scriptFileName + " " + "myargument");
Note : there is space between your filename and argument
This comment has been removed by the author.
DeleteHi Sim,
DeleteAs error says, may be your file is not there.
Check once manually whether file is there or not, if there then run your script through terminal.
*514.log looks for file ending with 514.log. May be there is no file present with this name
This comment has been removed by the author.
DeleteHi after login to unix server i do ssh to one particular user.
Deleteeg. ssh ames
how can i do this before executing script. i guess SSH is not happening hence getting No such file or directory.
Hi,
DeleteDo your user which is used to initiate session have permission to access that file.
Can you tell the exact command you are executing i.e channelExec.setCommand("sh "+ " ? ");
Hi Sim,
Deletecan you share screen shot of the command you run on Unix terminal.so that i can tell you exact issue.
Thanks
Hi Saket,
DeletePlease find below command
channelExec.setCommand("sh "+scriptFileName + " 05" + " 11");
Hi sim,
DeletePlease share screen shot of the command you run on Unix terminal.so that i can tell you exact issue.
i am also using the same code its working for wildcard, according to me its an issue on server side.
you can use without wildcard and check.
Hi sim,
Deleterun this command
grep customer /mnt/access_logs/ames/2015/10/05/*514.log | wc -l
on the terminal and please share the screen shot.
2093
Deletethis no displayed on screen
@sim are you login using same username from java code and on terminal.
DeleteI guess i need to login with ssh username. I am login with the server username... so I am just getting connected to unix server but dont have access to the path mentioned in script.
Deletemay be this is the root cause.
I will try...Thanks
Hi Sir, may i request to have detailed explanation for each line? Thanks
ReplyDeleteI have added some details as comments
DeleteLet me know if you need more
Thank you very much, one more question, how do i execute .sh file using this?
DeleteThis comment has been removed by the author.
DeleteThanks! This is awesome!
ReplyDeleteHello Kumar, thank very much. If I want to display file in GUI textarea. How I do?
ReplyDeleteHello Njike,
DeleteDo you want to display contents of that file to be displayed in GUI textarea?
The textarea is HTML based or Java SWT or other ?
Textarea java
ReplyDeleteHey Saket,
ReplyDeleteI tried this program and it's working fine in case of normal script. But it's failing when there is db connectivity in the script. And the error I am getting is - "DB connection failed while trying to connect ...". Could you please help here?
It usually works,i will need some more details about how you are making connection
DeleteActually, I am not making db connection in java code. It's there in script itself and also script is running fine when I run it from Unix server.
DeleteIt's just that this programs works fine in case of others script but failing in case script is having db connectivity.
This comment has been removed by the author.
ReplyDeleteYou have to create your own java class which will have main method in it. Then initialize the object of ShellExecuter and call executeFile method
DeleteOkay thanks .. I did it..but m getting " connection refused " as the error..
DeleteConnection refused is generally caused by wrong ports, provided your credentials are correct. Double check your port, i have used port 22 in my program
DeleteHi,
ReplyDeleteFirst of all i would like to thank you for nice post. my requirement is to run a someKSH.ksh(fileName) program in a particular directory(/home/process/input). By default it goes to home directory . when i change the directory with cd method and print out pwd it prints the right directory. But the program tries to execute the program in a home directory. How do i execute the ksh program in my desired location. Please see what i have done so far
channel=session.openChannel("exec");
((ChannelExec)channel).setCommand("someKSH.ksh processNow.txt");
channel.setInputStream(null);
((ChannelExec)channel).setErrStream(System.err);
InputStream in=channel.getInputStream();
channel.connect();
Result : someKSH.ksh not found
please help me with this, i am stuck here. thanks in advance
Hi,
ReplyDeleteyou can provide the full location of the script you want to use provided your user has permission for that. For instance
((ChannelExec)channel).setCommand("/somedir/someKSH.ksh processNow.txt");
Hi Saket,
ReplyDeleteThanks for sharing this useful code. I used it.
In my case, i have a .sh file when i run manually it will updated around 35 table and provied csv fiel in the end. But when i run through your code the execution is success but the tables are not getting updated and the csv file is also not getting created. Can you please help me out.
I am getting the below error: I am sure that I am using the right credential
ReplyDeletecom.jcraft.jsch.JSchException: Auth fail
at com.jcraft.jsch.Session.connect(Unknown Source)
I'm trying to execute a perl script through Java.
ReplyDeletecommand is - ./load_S_transaction.pl -v S
But I am getting an IOexception - The system cannot find the file specified
The script is very much present on the same location.
I tried giving entire path and not ./ yet no use.
Please help.
The login credentials you have used, does it have permissions for that file ?
DeleteHi Saket,
ReplyDeleteI would like to call a perl script in a Linux machine(remote) from Java application . So I can use channelExec.setCommand("perl "+ perlFileName with full path + " " + "myargument"); rite?? Also multiple user will hit my Java code at a time , does SSH will handle multiple request , do we have a thread pool like functionality in SSH ??
No, every unix system has inbuilt functionality of multiple SSH sessions. so you don't have to worry about that. Every system has some limitation, so it can have upper limit cap on max number of SSH sessions. How much you are anticipating ?
DeleteHow to send the script to server and get the result?
ReplyDeleteYou can a have a web server running, so that you can upload your scripts
DeleteHi saket, Please help me out to login super user through .setCommand() method. i am getting following error also not able to pass password in command.
ReplyDeleteCannot su to "username" : Authentication is denied.
can you show me your code ?
DeleteChannel channel = session.openChannel("exec");
Delete((ChannelExec) channel).setPty(true);
((ChannelExec) channel).setCommand("su - username");
BufferedReader in=new BufferedReader(new InputStreamReader(channel.getInputStream()));
OutputStream out=channel.getOutputStream();
channel.connect();
out.write((“password”+"\n").getBytes());
out.flush();
This comment has been removed by the author.
Deletedid u get any solution ?
Deletesuperb explanation as well as code! tq sooo much Saket kumar, for ur wonderful code!!! but i have a small doubt in this,,, iam using this code to run an sh file which has pl/sql stored procedure which is located in linux box --> /u01/oradata/arun/dbclone.sh --> when i connect to linux, and execute this file, its running in the backend only once, again its not running after some time period its running why is it so...and my 1 more doubt is when i run this code i'm able to run the sh file in the backend,but i need to get its results in my console,,,so that i can move it to front end, is it possible???
ReplyDeleteAre you trying to run a periodic task ? then you better use cron jobs , once triggered it will run periodically at specifed time. To get results on console you must echo the output from sh file. It will be captured in the input stream used in above program
Deleteok i vl do that,,but its not periodically done... it should when i run this program.. but in my console it shows connected, file is executing,, but in linux the script is not running...this is my code, plssssss help me its urgent..
ReplyDeletepackage com.inhouse;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
public class AccessingSh {
ResultSet rs=null;
Connection con=null;
Statement st=null;
PreparedStatement ps=null;
static String scriptFileName=null;
public static void main(String[] args) {
String host="xxx.xxx.x.xx";
String user="xxxx";
String password="xxx123";
String command1="/u01/oradata/arun/dbclone.sh";
try{
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
JSch jsch = new JSch();
Session session=jsch.getSession(user, host, 22);
session.setPassword(password);
session.setConfig(config);
session.connect();
System.out.println("Connected");
Channel channel=session.openChannel("exec");
((ChannelExec) channel).setCommand(command1);
((ChannelExec) channel).setErrStream(System.err);
channel.connect();
System.out.println("file is ex");
channel.disconnect();
session.disconnect();}
catch(Exception e){}
}}
HOW TO PASS arguments for this particular script
DeleteSame as you use to do it normally on terminal,
Deleteex : channelExec.setCommand("sh "+scriptFileName + " " + "myargument");
Note : there is space between your filename and argument
my sh file (dbclone.sh) is in /u01/oradata/arun/dbclone.sh is given as follows:
ReplyDeletea=`sqlplus -s "/ as sysdba" < 'clone',
job_type => 'EXECUTABLE',
job_action => '/home/oracle/project/clone_db_auto/clone_test_automated_full.sh',
start_date => SYSDATE,
repeat_interval => 'NULL',
enabled => TRUE,
auto_drop => TRUE,
comments => 'Calling shell script from Oracle'
);
dbms_output.put_line('Cloning Mode Activated');
end;
/
exit;
EOF`
and after this i have to call this script dbrunn.sh from the same path and get the output from here , i tried to call both the scripts using ur code but unable to do it
dbrunn.sh file is:
a=`sqlplus -s "/ as sysdba" <<EOF
exec CLONING;
exit;
EOF`
echo $a
hi Sir, when I am printing a string using "Example" , it is getting captured in Inputstream, but variable is not getting captured
ReplyDeletee.q.
abc =Test;
echo "$abc"
@saket kumar :- Awesome
ReplyDeleteGreat job! thanks for sharing.
ReplyDeleteBut I wish to know; if the shell script I am running is on my local systems (windows) and I want it to run on on a remote Linux box, what changes Can I make? I tried a couple already but its failing.
Thanks for your help
Great Work it worked :)
ReplyDeleteHi,
ReplyDeleteThe code is working perfectly fine. It is connecting to the linux server and i'm able to run the shell script. But in my script there are 2 files which are being used and since i'm giving only the path to that script i'm not getting the output.
Hi,
ReplyDeleteI'm executing a script which does an postgreSQL dump via pg_dump but I'm not getting the shell output like:
pg_dump: reading extensions
pg_dump: identifying extension members
pg_dump: reading schemas
pg_dump: reading user-defined tables
pg_dump: reading user-defined functions
.....
How can I capture this output?
Hi,
ReplyDeleteThis is bit urgent for me. Any prompt reply is appreciated !!!
Above code ".suggest the usage of default authentication method as "Keyboard interactive.
1. I am getting "Auth cancel" for above code.;
2. When i add a code session.setpassword("preferredAuthentication","password"- exception goes but then i get another expception as "Auth Failure". My query is related to that . My password is valid and I can connect to server and execute shell script using java.
3.Initially in debug mode, I was getting password as null string when called for setpassword method
4. Later I tried "String".getbytes() and passed as parameter to setpassword method
I am trying to understand is using "Keyboard interactive" method only valid way of providing password. Is it like when we give a string to setpassword , it expects password in encoded form and whats way to handle it
I want this or similar code to execute the Linux shell script from by servlet in web application. Can you please help me with that. I tried above code but it's giving me compilation error. Thanks
ReplyDeleteYou check once again, have you added library in your class path ?
DeleteI am trying to do something similar. But in my case, the scripts are present on the local server instead of the remote server. I have already explored the option of sftp-ing the script to the remote machine and then executing the script. But that option is not feasible for me. Other option is that I can convert the whole script into a string and then send it as a command. I want to know is there a better way than sending the contents of the script as a command?
ReplyDeleteHi Saket,
ReplyDeleteI have a use case where in I have to connect to a ssh terminal using
ssh cli@terminal_ip. when you connect, it will ask for the username and password, there you have to provide your username and password and execute the commands on the terminal.
With the help of this post, I am able to connect by using the following code to get the session
final Session session = jsch.getSession("cli", terminal_ip, port);
but after this, I am not able to enter the username and password for the terminal. Could you please help me in achieving that??
"cli" is the username !
DeleteYou can follow the next steps
session.setConfig("StrictHostKeyChecking", "no");
session.setPassword(PASSWORD);
session.connect();
Hi Saket,
ReplyDeleteNo Cli is not the username..
Cli is a terminal through which you can do some configurations on the node.
after doing ssh cli@nodeip
you will be asked to provide the admin user and credentials for the user like this..
enter admin username :
enter admin password :
Here I need to give the admin username and password using java code.
Could you please let me know how to do that?
Thanks,
Mahesh
Hi,
ReplyDeleteI needed to use jsch to run some commands on a remote server in the production environment and hence cannot use the "StrictHostKeyChecking", "no" configuration. Without this, I get a session is down warning. How am I to setup the host at the remote server and make this a dynamic process? I've putty-ed into the remote server and played around so my local machine should be authenticated.
Thanks,
Pranav
Great! Thanks a lot :)
ReplyDeleteHi, I am trying to execute command on a Linux machine. Eclipse stays as it is after i execute the statement "session.connect();" I have given a sysout after it but the control doesn't reach there nor any exception is thrown.
ReplyDeleteHi Saket,
ReplyDeleteMy requirement is to do CVS merge automation. I have some list of commands in sh file. Could you share how to get the params in sh file which we are passing in our class file.
is it possible to navigate to particular path after connecting to the server? I have written the selenium scripts to connect to the box, But not able to navigate. Please suggest me how to do this?
ReplyDeleteThere can be multiple ways to achieve it.
Delete1. Write a shell script for all your needs in one file and execute it directly.
2. You can also write series of commands in channel exec method ie ((ChannelExec)channel).setCommand("somescript.sh; cd /usr; pwd");
3. Instead of ChanelExec use ChannelShell, ChannelShell comes handy for interactive options.
Hi,
ReplyDeleteI have multiple commands to be executed on SSH. How would i do that.
Could you please help me on that.
Thanks.
Write all your commands in a .sh file and execute it.
DeleteHi Saket,
ReplyDeleteI have tried to run a .sh file in a remote server, but while execute the java code while connecting to session throwing the below error
Session.connect: java.lang.NullPointerException. Please provide your suggestion to solve this issue.
Thanks
With that information i can only say your session is not initialised. Check details like host, port and password. Are you able to connect via SSH using same details ?
DeleteYes, I can connect via SSH using the same details.. thank you for the quick reply ..please help me to sort this out.
DeleteCan you show us your code ?
DeleteHi Saket,
DeleteWhile using port 21 with the same log-in details i am getting the below error,
java.lang.ArrayIndexOutOfBoundsException: length == 892547100 off == 8 buffer length == 20480
Please let me know if i need any config details regarding buffer size or length.
As you asked please find the code below,
package linux;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
public class Connect {
public void executeFile(String scriptFileName,String argument, String user, String host, String password,int port)
{
try{
String result;
JSch jsch = new JSch();
Session session = jsch.getSession(user, host, port);
Hashtable h = new Hashtable();
h.put("StrictHostKeyChecking", "no");
h.put("GSSAPIAuthentication","no");
h.put("GSSAPIKeyExchange", "no");
session.setConfig(h);
session.setPassword(password);
System.out.println("before");
session.connect();
System.out.println("After");
ChannelExec channelExec = (ChannelExec)session.openChannel("exec");
InputStream in = channelExec.getInputStream();
channelExec.setCommand("sh "+scriptFileName+" "+argument);
channelExec.connect();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = reader.readLine()) != null)
{
result=line+"\n";
System.out.println("reader" +result);
}
int exitStatus = channelExec.getExitStatus();
System.out.println("ExitStatus "+exitStatus);
channelExec.disconnect();
session.disconnect();
}catch(Exception e){
System.out.println(e.getStackTrace());
}
}}
Hi ,
ReplyDeleteCan we run power shell script using this code.
Thanks
Sarvjeet
Hi. Great work.
ReplyDeleteI am trying to execute a TCL script on the Linux server. I am able to connect to the server but I get the "proc: command not found" error. Can you guide me on what is missing..
Hii , actually i have tried it . but this code doesn't work.
ReplyDeleteThis comment has been removed by the author.
ReplyDeletesession.connect goes inte idle state, can you find the reason
ReplyDeleteOnly if you can share what you have done.
DeleteHi, actually I'm trying to connect to remote server with credentials similar to yours. Initially I'm getting the port issue so I changed the port number which is available. My program runs till session.connect() method and from there nothing happens. When I pass the parameter as timeout it throws Timeout excpetion. I checked through netstat that my connection is established on the specified port but it is unable to create session.
DeleteThe program is similar to yours only the static variables are different
DeleteIt will throw an exception is session is already connected, without seeing your code it's hard to debug
Deletepublic List executeFile(String scriptFileName)
Delete{
List result = new ArrayList();
try
{
/**
* Create a new Jsch object
* This object will execute shell commands or scripts on server
*/
JSch jsch = new JSch();
/*
* Open a new session, with your username, host and port
* Set the password and call connect.
* session.connect() opens a new connection to remote SSH server.
* Once the connection is established, you can initiate a new channel.
* this channel is needed to connect to remotely execution program
*/
Session session = jsch.getSession(USERNAME, host, port);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.setPassword(PASSWORD);
session.connect();
//create the excution channel over the session
ChannelExec channelExec = (ChannelExec)session.openChannel("exec");
// Gets an InputStream for this channel. All data arriving in as messages from the remote side can be read from this stream.
InputStream in = channelExec.getInputStream();
// Set the command that you want to execute
// In our case its the remote shell script
channelExec.setCommand("cmd "+scriptFileName);
// Execute the command
channelExec.connect();
// Read the output from the input stream we set above
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line;
//Read each line from the buffered reader and add it to result list
// You can also simple print the result here
while ((line = reader.readLine()) != null)
{
result.add(line);
}
//retrieve the exit status of the remote command corresponding to this channel
int exitStatus = channelExec.getExitStatus();
//Safely disconnect channel and disconnect session. If not done then it may cause resource leak
channelExec.disconnect();
session.disconnect();
if(exitStatus < 0){
// System.out.println("Done, but exit status not set!");
}
else if(exitStatus > 0){
// System.out.println("Done, but with error!");
}
else{
// System.out.println("Done!");
}
}
catch(Exception e)
{
System.err.println("Error: " + e);
}
return result;
}
this is the method and I call it from main() with parameters
Deleteobj.executeFile(".bat file path")
And as I said there is no exception it waits for very long time at session.connect() method.
DeleteHi, if someone can resolve the above issue, then please take the lead
ReplyDeleteHello Saket
ReplyDeleteThanks for the program
I tried to use the above program but it is not working for me and I am getting exit status 127
Can you please help
status 127 indicates a 'command not found error'
DeleteThanks for quick reply Saket but what can be the reason for this,I also tried by giving full path of my sh file but no help
DeleteCan you please suggest some quick debug step for this to work
Script full is path:Path/abc/xyz/script.sh
DeleteI tried with
String co="Path/abc/xyz/script.sh"
channelExec.setCommand("sh "+co);
Can you please what mistake I am doing
try with the absolute path starting from '/'
DeleteTried same now I am getting 101 exit status
DeleteCheck couple of things:
Delete1. Can you run the same script successfully using terminal with no errors.
2. Do 'user' which you used to login has necessary privilege to run that script file
Let me know if you are able to resolve that session.connect() issue
DeleteHi Saket,
DeleteI have same issue getting 127 Error Code.My DB package is calling JSCH class using command 'sh execute_file.ksh ' and in JSCH class it is setting the command as
session = jSch.getSession(sftp_user, sftp_host, 2000);
....
((ChannelExec) channel).setCommand(command);
then it throughs error as below :
Inside sendCommand available
Block#2 Inside sendCommand: Exception: Others
Exception from Block#2.B: Invalid command used !!sh execute_file.ksh 207158 334357
Inside sendCommand: FINALLY Disconnections executed
6. function call above: fn_sas_file_execution response: 127:ERROR: Error while executing SAS Macro.
manual execution works perfect ..only issue through JSCH .Please suggest
Hi, the command is to execute bat file simply mentioning the path to it like "C:\users\userfolder\xyz.bat", you can try some valid commands.
ReplyDeleteSimply put, add any valid cmd command as parameter to executefile() method
ReplyDeleteThank you very much for the code.
ReplyDeleteHow do I execute multiple commands instead of one like below."channelExec.setCommand("sh "+scriptFileName);"
ReplyDeleteMy requirement is to run few other commands before executing a script after logging into a host.
java.util.Properties config = new java.util.Properties();
ReplyDeleteconfig.put("StrictHostKeyChecking", "no");
config.put("PreferredAuthentications", "publickey,keyboard-interactive,password");
session.setConfig(config);
Hi,
ReplyDeleteI am trying to run powershell script on remote server using Java code getting the exception when it tries to connect jsch.getsession(username, host,port) here i am using port 22
Exception: com.jcraft.jsch.jschexception:session.connect: java.net.socketexception: connection reset while using
Thank you for sharing this tutorial. The basics of client-server programming and networking can be helpful in understanding the client-server architecture. I appreciate the author's efforts in writing this amazing article. Great blog, glad to come across this. Cracking the coding interview
ReplyDelete