ALL is Well!

敏捷是一条很长的路,摸索着前进着

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  30 随笔 :: 23 文章 :: 71 评论 :: 0 Trackbacks
此程序需要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:
/**
 * 远程执行shell脚本类
 * 
@author l
 
*/

public class RmtShellExecutor {
    
    
/**  */
    
private Connection conn;
    
/** 远程机器IP */
    
private String     ip;
    
/** 用户名 */
    
private String     usr;
    
/** 密码 */
    
private String     psword;
    
private String     charset = Charset.defaultCharset().toString();

    
private static final int TIME_OUT = 1000 * 5 * 60;

    
/**
     * 构造函数
     * 
@param param 传入参数Bean 一些属性的getter setter 实现略
     
*/

    
public RmtShellExecutor(ShellParam param) {
        
this.ip = param.getIp();
        
this.usr = param.getUsername();
        
this.psword = param.getPassword();
    }


    
/**
     * 构造函数
     * 
@param ip
     * 
@param usr
     * 
@param ps
     
*/

    
public RmtShellExecutor(String ip, String usr, String ps) {
        
this.ip = ip;
        
this.usr = usr;
        
this.psword = ps;
    }


    
/**
     * 登录
     * 
     * 
@return
     * 
@throws IOException
     
*/

    
private boolean login() throws IOException {
        conn 
= new Connection(ip);
        conn.connect();
        
return conn.authenticateWithPassword(usr, psword);
    }


    
/**
     * 执行脚本
     * 
     * 
@param cmds
     * 
@return
     * 
@throws Exception
     
*/

    
public int exec(String cmds) throws Exception {
        InputStream stdOut 
= null;
        InputStream stdErr 
= null;
        String outStr 
= "";
        String outErr 
= "";
        
int ret = -1;
        
try {
            
if (login()) {
                
// Open a new {@link Session} on this connection
                Session session = conn.openSession();
                
// Execute a command on the remote machine.
                session.execCommand(cmds);
                
                stdOut 
= new StreamGobbler(session.getStdout());
                outStr 
= processStream(stdOut, charset);
                
                stdErr 
= new StreamGobbler(session.getStderr());
                outErr 
= processStream(stdErr, charset);
                
                session.waitForCondition(ChannelCondition.EXIT_STATUS, TIME_OUT);
                
                System.out.println(
"outStr=" + outStr);
                System.out.println(
"outErr=" + outErr);
                
                ret 
= session.getExitStatus();
            }
 else {
                
throw new AppException("登录远程机器失败" + ip); // 自定义异常类 实现略
            }

        }
 finally {
            
if (conn != null{
                conn.close();
            }

            IOUtils.closeQuietly(stdOut);
            IOUtils.closeQuietly(stdErr);
        }

        
return ret;
    }


    
/**
     * 
@param in
     * 
@param charset
     * 
@return
     * 
@throws IOException
     * 
@throws UnsupportedEncodingException
     
*/

    
private String processStream(InputStream in, String charset) throws Exception {
        
byte[] buf = new byte[1024];
        StringBuilder sb 
= new StringBuilder();
        
while (in.read(buf) != -1{
            sb.append(
new String(buf, charset));
        }

        
return sb.toString();
    }


    
public static void main(String args[]) throws Exception {
        RmtShellExecutor exe 
= new RmtShellExecutor("***.**.**.***""sshapp""sshapp");
        
// 执行myTest.sh 参数为java Know dummy
        System.out.println(exe.exec("sh /webapp/myshell/myTest.sh java Know dummy"));
//        exe.exec("uname -a && date && uptime && who");
    }

}

执行后结果:
outStr=java Know 3
outErr
=
0 // getExitStatus方法的返回值

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

/**
 * Contains constants that can be used to specify what conditions to wait for on
 * a SSH-2 channel (e.g., represented by a {
@link Session}).
 *
 * 
@see Session#waitForCondition(int, long)
 *
 * 
@author Christian Plattner, plattner@inf.ethz.ch
 * 
@version $Id: ChannelCondition.java,v 1.6 2006/08/11 12:24:00 cplattne Exp $
 
*/


public abstract interface ChannelCondition
{
    
/**
     * A timeout has occurred, none of your requested conditions is fulfilled.
     * However, other conditions may be true - therefore, NEVER use the "=="
     * operator to test for this (or any other) condition. Always use
     * something like <code>((cond & ChannelCondition.CLOSED) != 0)</code>.
     
*/

    
public static final int TIMEOUT = 1;

    
/**
     * The underlying SSH-2 channel, however not necessarily the whole connection,
     * has been closed. This implies <code>EOF</code>. Note that there may still
     * be unread stdout or stderr data in the local window, i.e, <code>STDOUT_DATA</code>
     * or/and <code>STDERR_DATA</code> may be set at the same time.
     
*/

    
public static final int CLOSED = 2;

    
/**
     * There is stdout data available that is ready to be consumed.
     
*/

    
public static final int STDOUT_DATA = 4;

    
/**
     * There is stderr data available that is ready to be consumed.
     
*/

    
public static final int STDERR_DATA = 8;

    
/**
     * EOF on has been reached, no more _new_ stdout or stderr data will arrive
     * from the remote server. However, there may be unread stdout or stderr
     * data, i.e, <code>STDOUT_DATA</code> or/and <code>STDERR_DATA</code>
     * may be set at the same time.
     
*/

    
public static final int EOF = 16;

    
/**
     * The exit status of the remote process is available.
     * Some servers never send the exist status, or occasionally "forget" to do so.
     
*/

    
public static final int EXIT_STATUS = 32;

    
/**
     * The exit signal of the remote process is available.
     
*/

    
public static final int EXIT_SIGNAL = 64;

}

当我们把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\下的例子吧。

本文为原创,欢迎转载,转载请注明出处BlogJava
posted on 2010-09-26 13:03 李 明 阅读(13540) 评论(7)  编辑  收藏 所属分类: Java

评论

# re: Java SSH远程执行Shell脚本实现 2010-09-26 22:22 大道至简
我虽不是很明白,但感觉写的很好哈!  回复  更多评论
  

# re: Java SSH远程执行Shell脚本实现 2011-02-25 19:52 wx
有批量执行命令的例子吗?  回复  更多评论
  

# re: Java SSH远程执行Shell脚本实现 2011-02-28 11:06 Ronaldo
@wx
不好意思,没有写过。
自己实现一下吧,大概原理应该差不多。  回复  更多评论
  

# re: Java SSH远程执行Shell脚本实现 2012-02-06 17:20 asialee
ssh2和JSch那个性能好?  回复  更多评论
  

# re: Java SSH远程执行Shell脚本实现 2013-05-19 02:21 cnskylee
ShellParam 是什么?而且导入的包也不写出来,还有IOUtil是你自己写的?还是什么包里面的啊?  回复  更多评论
  

# re: Java SSH远程执行Shell脚本实现 2013-05-19 02:23 cnskylee
JavaSFTP可以连接主机,执行文件操作;JavaSSH主要是连接远程主机,执行shell脚本。菜鸟的初解  回复  更多评论
  

# re: Java SSH远程执行Shell脚本实现 2015-04-06 23:36 tlone
请问如果脚本中的命令为top的话请问该怎么返回执行结果呢?  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: