Java SSH远程执行Shell脚本实现

48 篇文章 0 订阅
10 篇文章 0 订阅

此程序需要ganymed-ssh2-build210.jar包。
下载地址:http://www.ganymed.ethz.ch/ssh2/
为了调试方便,可以将\ganymed-ssh2-build210\src下的代码直接拷贝到我们的工程里,
此源码的好处就是没有依赖很多其他的包,拷贝过来干干净净。

此程序的目的是执行远程机器上的Shell脚本。
远程机器IP:***.**.**.***
用户名:sshapp
密码:sshapp
登录后用pwd命令,显示当前目录为:/sshapp.
在/sshapp/myshell/目录下有myTest.sh文件,内容如下:
 

echo $ 1  $ 2  $ #
#print $1


我们的Java代码RmtShellExecutor.java:
 

 
 
  1. /** *//**  
  2.  * 远程执行shell脚本类  
  3.  * @author l  
  4.  */ 
  5. public class RmtShellExecutor {  
  6.       
  7.     /** *//**  */ 
  8.     private Connection conn;  
  9.     /** *//** 远程机器IP */ 
  10.     private String     ip;  
  11.     /** *//** 用户名 */ 
  12.     private String     usr;  
  13.     /** *//** 密码 */ 
  14.     private String     psword;  
  15.     private String     charset = Charset.defaultCharset().toString();  
  16.  
  17.     private static final int TIME_OUT = 1000 * 5 * 60;  
  18.  
  19.     /** *//**  
  20.      * 构造函数  
  21.      * @param param 传入参数Bean 一些属性的getter setter 实现略  
  22.      */ 
  23.     public RmtShellExecutor(ShellParam param) {  
  24.         this.ip = param.getIp();  
  25.         this.usr = param.getUsername();  
  26.         this.psword = param.getPassword();  
  27.     }  
  28.  
  29.     /** *//**  
  30.      * 构造函数  
  31.      * @param ip  
  32.      * @param usr  
  33.      * @param ps  
  34.      */ 
  35.     public RmtShellExecutor(String ip, String usr, String ps) {  
  36.         this.ip = ip;  
  37.         this.usr = usr;  
  38.         this.psword = ps;  
  39.     }  
  40.  
  41.     /** *//**  
  42.      * 登录  
  43.      *   
  44.      * @return  
  45.      * @throws IOException  
  46.      */ 
  47.     private boolean login() throws IOException {  
  48.         conn = new Connection(ip);  
  49.         conn.connect();  
  50.         return conn.authenticateWithPassword(usr, psword);  
  51.     }  
  52.  
  53.     /** *//**  
  54.      * 执行脚本  
  55.      *   
  56.      * @param cmds  
  57.      * @return  
  58.      * @throws Exception  
  59.      */ 
  60.     public int exec(String cmds) throws Exception {  
  61.         InputStream stdOut = null;  
  62.         InputStream stdErr = null;  
  63.         String outStr = "";  
  64.         String outErr = "";  
  65.         int ret = -1;  
  66.         try {  
  67.             if (login()) {  
  68.                 // Open a new {@link Session} on this connection  
  69.                 Session session = conn.openSession();  
  70.                 // Execute a command on the remote machine.  
  71.                 session.execCommand(cmds);  
  72.                   
  73.                 stdOut = new StreamGobbler(session.getStdout());  
  74.                 outStr = processStream(stdOut, charset);  
  75.                   
  76.                 stdErr = new StreamGobbler(session.getStderr());  
  77.                 outErr = processStream(stdErr, charset);  
  78.                   
  79.                 session.waitForCondition(ChannelCondition.EXIT_STATUS, TIME_OUT);  
  80.                   
  81.                 System.out.println("outStr=" + outStr);  
  82.                 System.out.println("outErr=" + outErr);  
  83.                   
  84.                 ret = session.getExitStatus();  
  85.             } else {  
  86.                 throw new AppException("登录远程机器失败" + ip); // 自定义异常类 实现略  
  87.             }  
  88.         } finally {  
  89.             if (conn != null) {  
  90.                 conn.close();  
  91.             }  
  92.             IOUtils.closeQuietly(stdOut);  
  93.             IOUtils.closeQuietly(stdErr);  
  94.         }  
  95.         return ret;  
  96.     }  
  97.  
  98.     /** *//**  
  99.      * @param in  
  100.      * @param charset  
  101.      * @return  
  102.      * @throws IOException  
  103.      * @throws UnsupportedEncodingException  
  104.      */ 
  105.     private String processStream(InputStream in, String charset) throws Exception {  
  106.         byte[] buf = new byte[1024];  
  107.         StringBuilder sb = new StringBuilder();  
  108.         while (in.read(buf) != -1) {  
  109.             sb.append(new String(buf, charset));  
  110.         }  
  111.         return sb.toString();  
  112.     }  
  113.  
  114.     public static void main(String args[]) throws Exception {  
  115.         RmtShellExecutor exe = new RmtShellExecutor("***.**.**.***""sshapp""sshapp");  
  116.         // 执行myTest.sh 参数为java Know dummy  
  117.         System.out.println(exe.exec("sh /webapp/myshell/myTest.sh java Know dummy"));  
  118. //        exe.exec("uname -a && date && uptime && who");  
  119.     }  


执行后结果:
 

outStr = java Know  3
outErr
=
0   //  getExitStatus方法的返回值


 注:一般情况下shell脚本正常执行完毕,getExitStatus方法返回0。
此方法通过远程命令取得Exit Code/status。但并不是每个server设计时都会返回这个值,如果没有则会返回null。
在调用getExitStatus时,要先调用WaitForCondition方法,通过ChannelCondition.java接口的定义可以看到每个条件的具体含义。见以下代码:
ChannelCondition.java
 

 
 
  1. package ch.ethz.ssh2;  
  2.  
  3. /** *//**  
  4.  * Contains constants that can be used to specify what conditions to wait for on  
  5.  * a SSH-2 channel (e.g., represented by a {@link Session}).  
  6.  *  
  7.  * @see Session#waitForCondition(int, long)  
  8.  *  
  9.  * @author Christian Plattner, plattner@inf.ethz.ch  
  10.  * @version $Id: ChannelCondition.java,v 1.6 2006/08/11 12:24:00 cplattne Exp $  
  11.  */ 
  12.  
  13. public abstract interface ChannelCondition  
  14. {  
  15.     /** *//**  
  16.      * A timeout has occurred, none of your requested conditions is fulfilled.  
  17.      * However, other conditions may be true - therefore, NEVER use the "=="  
  18.      * operator to test for this (or any other) condition. Always use  
  19.      * something like <code>((cond & ChannelCondition.CLOSED) != 0)</code>.  
  20.      */ 
  21.     public static final int TIMEOUT = 1;  
  22.  
  23.     /** *//**  
  24.      * The underlying SSH-2 channel, however not necessarily the whole connection,  
  25.      * has been closed. This implies <code>EOF</code>. Note that there may still  
  26.      * be unread stdout or stderr data in the local window, i.e, <code>STDOUT_DATA</code>  
  27.      * or/and <code>STDERR_DATA</code> may be set at the same time.  
  28.      */ 
  29.     public static final int CLOSED = 2;  
  30.  
  31.     /** *//**  
  32.      * There is stdout data available that is ready to be consumed.  
  33.      */ 
  34.     public static final int STDOUT_DATA = 4;  
  35.  
  36.     /** *//**  
  37.      * There is stderr data available that is ready to be consumed.  
  38.      */ 
  39.     public static final int STDERR_DATA = 8;  
  40.  
  41.     /** *//**  
  42.      * EOF on has been reached, no more _new_ stdout or stderr data will arrive  
  43.      * from the remote server. However, there may be unread stdout or stderr  
  44.      * data, i.e, <code>STDOUT_DATA</code> or/and <code>STDERR_DATA</code>  
  45.      * may be set at the same time.  
  46.      */ 
  47.     public static final int EOF = 16;  
  48.  
  49.     /** *//**  
  50.      * The exit status of the remote process is available.  
  51.      * Some servers never send the exist status, or occasionally "forget" to do so.  
  52.      */ 
  53.     public static final int EXIT_STATUS = 32;  
  54.  
  55.     /** *//**  
  56.      * The exit signal of the remote process is available.  
  57.      */ 
  58.     public static final int EXIT_SIGNAL = 64;  
  59.  


当我们把myTest.sh修改为如下内容:
 

echo $ 1  $ 2  $ #
print  $ 1

由于我使用的linux机器上没有print命令,所以print $1会报错:command not found。

接下来再让我们执行一下,看看控制台的结果:
 

outStr = java Know  3
outErr
=/ sshapp / myshell / myTest.sh: line  2 : print: command not found
127

此时shell脚本出现错误,getExitStatus方法返回127.

在实际应用中,可以将outStr和outErr记录到日志中,以便维护人员查看shell的执行情况,
而getExitStatus的返回值,可以认为是此次执行是否OK的标准。

其他代码请看\ganymed-ssh2-build210\examples\下的例子吧。 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值