java 新进程(ProcessBuilder) 远程(Ganymed SSH-2)

转载自: http://www.youzitool.com/index/detail/id/23.html


我们在日常开发中,有时候会遇到触发一个linux命令,比如清理临时文件,或者触发一个shell命令。那么这个时候就需要通过java去调用shell命令。 这里我们使用java自带的ProcessBuilder 来完成任务。ProcessBuilder类是用于创建操作系统进程.

//其中List<String> orders 就是待执行的命令
//比如 orders.add("hadoop")
// orders.add("fs")
// orders.add("-ls")
// orders.add("filePath+fileName")

public static List<String> execute(List<String> orders)
            throws IOException, InterruptedException {
        List<String> sb = new ArrayList<String>();

        Process p = null;
        InputStream is = null;
        BufferedReader br = null;

        try {
            //构造ProcessBuilder,并将需要执行的命令传入
            ProcessBuilder pb = new ProcessBuilder(orders);
            //启动进程,并获取输出流
            p = pb.redirectErrorStream(true).start();

            is = p.getInputStream();
            br = new BufferedReader(new InputStreamReader(is));
            String line;
            while ((line = br.readLine()) != null) {
                sb.add(line);
                LoggerUtil.error("util", "info", line);
            }
            //等待进程
            p.waitFor();

            return sb;
        } finally {
            if (p != null) {
                close(p.getOutputStream());
                close(p.getInputStream());
                close(p.getErrorStream());
                p.destroy();
            }
            if (br != null) {
                br.close();
            }
            if (is != null) {
                is.close();
            }
        }
    }

    private static void close(Closeable c) {
        if (c != null) {
            try {
                c.close();
            } catch (IOException e) {
            }
        }
    }
}


这样就能够通过hadoop 获取文件大小。但这里会有一个隐藏的坑。那就是ProcessBuilder 的环境变量问题

如果你没有在脚本里指明hadoop 依赖的环境变量路径,那么执行就会报错,所以我们需要依赖系统的环境变量,只需要在 pb  = new ProcessBuilder 对象之后,pb.environment(); 就可以获取到系统默认的环境变量。


通过上面的方式就能够执行本地shell命令,这时候可能又会有另外一个需求,通过本机远程ssh到另外一台机器上去执行shell命令,这种使用方式经常用于一台机器集群管理其他机器的需求。

这里我们使用 Ganymed SSH-2 for Java http://www.ganymed.ethz.ch/ssh2/

Ganymed SSH-2 for Java is a library which implements the SSH-2 protocol in pure Java (tested on J2SE 1.4.2 and 5.0). It allows one to connect to SSH servers from within Java programs. It supports SSH sessions (remote command execution and shell access), local and remote port forwarding, local stream forwarding, X11 forwarding, SCP and SFTP. There are no dependencies on any JCE provider, as all crypto functionality is included.


Ganymed SSH-2 for Java是用纯Java实现SSH-2协议的一个包。可以利用它直接在Java程序中连接SSH服务器。Ganymed SSH-2支持SSH对话(远程命令执行和shell访问),本地和远程端口转发,本地数据流转发,X11转发和SCP。这些都没有依赖任何JCE provider,而且所有这些都包含加密的功能。

//cmd 是待执行的shell命令.
//logFile 执行过程中,记录返回日志的文件
  public ShellResult<String> execute(String cmd, String logFile){
        if(StringUtils.isBlank(cmd)){
            return new ShellResult<String>("cmd_is_null");
        }
        if(StringUtils.isBlank(logFile)){
            return new ShellResult<String>("logFile_is_null");
        }
        ShellResult<String> result = new ShellResult<String>("no_exec");
        InputStream stdOut;
        InputStream stdErr;
        try{
            if(login()){
                //打开一个会话
                Session session = conn.openSession();
                //执行远程命令
                session.execCommand(cmd);
                stdOut = new StreamGobbler(session.getStdout());
                stdErr = new StreamGobbler(session.getStderr());

                BufferedReader stdOutRead = new BufferedReader(new InputStreamReader(stdOut));
                String line = stdOutRead.readLine();
                while (line != null){
                    LoggerUtil.error(logFile, "INFO", line);
                    line = stdOutRead.readLine();
                }
                BufferedReader stdErrRead = new BufferedReader(new InputStreamReader(stdErr));
                line = stdErrRead.readLine();
                while (line != null){
                    LoggerUtil.error(logFile, "Exception", line);
                    line = stdOutRead.readLine();
                }
               //这里要等待会话结束返回
                session.waitForCondition(ChannelCondition.EXIT_STATUS, Long.MAX_VALUE);
                //根据会话返回结果判断执行是否成功
                int ret = session.getExitStatus();
                if(ret == 0){
                    result.setSuccess(true);
                }else{
                    result.setErrorMsg("exec_error,ret="+ret);
                }
                session.close();
            }
        }catch (Exception e){
            result.setErrorMsg(e.getMessage());
        }finally {
            conn.close();
        }
        return result;
    }
    private boolean login() throws IOException{
        //连接ip地址
        conn = new Connection("127.0.0.1");
        conn.connect();
        //等待返回,连接成功则返回true,第一个参数为用户名,第二个参数为密码
        return conn.authenticateWithPassword("user","password");
    }


你可能感兴趣的:(java,shell,进程,ssh2)