• Java SSH远程执行Shell脚本实现(转)


    前言

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

    简介

    目的:是执行远程机器上的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-build210examples下的例子吧。

    转自:http://rainyear.iteye.com/blog/1339825

  • 相关阅读:
    在Eclipse中写第一个hibernate小例子
    [转载]mysql 学习笔记
    hibernate.cfg.xml 配置(摘录)
    j2ee笔试题目
    J2EE综合—Struts常见错误的全面汇总
    在Eclipse中写第一个hibernate小例子
    j2ee笔试题目
    hibernate.cfg.xml 配置(摘录)
    [转载]mysql 学习笔记
    J2EE综合—Struts常见错误的全面汇总
  • 原文地址:https://www.cnblogs.com/tv151579/p/3288266.html
Copyright © 2020-2023  润新知