Java执行shell脚本文件完整代码

版权声明:本文为博主原创文章,转载请注明作者和出处! https://blog.csdn.net/tterminator/article/details/82227394

一、背景

最近要下线一台历史遗留的物理机,在整理该机的crontab任务时,发现有不少纯shell脚本形式的定时任务,决定使用Java写一个执行shell脚本文件的通用工具类。

二、实现方式

Java执行shell脚本文件共有两种方式,两种方式的共同点均是创建独立的process执行脚本文件。

方式1:通过Runtime创建process
Process process = Runtime.getRuntime().exec(cmd);
方式2:创建原生Java对象ProcessBuilder
    public ProcessBuilder(String... command) {
        this.command = new ArrayList<>(command.length);
        for (String arg : command)
            this.command.add(arg);
    }

如果遇到权限问题,可以使用ProcessBuilder对象先改变脚本执行权限后,再使用ProcessBuilder对象执行该脚本,例如:
ProcessBuilder builder = new ProcessBuilder(“/bin/chmod”, “755”, tempFile.getPath());
Process process = builder.start();
int rc = process.waitFor();

虽然Java执行shell脚本时有两种方式,其实方式1本质上还是通过创建ProcessBuilder来执行shell脚本的,详见Runtime类如下exec函数代码:

    public Process exec(String[] cmdarray, String[] envp, File dir)
        throws IOException {
        return new ProcessBuilder(cmdarray)
            .environment(envp)
            .directory(dir)
            .start();
    }

三、代码实现

Java执行shell脚本文件完整代码如下

/**
 * Java执行shell脚本工具类
 */
public class ShellExcutor {
    private static Logger log = LoggerFactory.getLogger("shell_logger");

    /**
     * Java执行shell脚本入口
     * @param shellName 脚本文件名
     * @throws Exception
     */
    public void service(String shellName) throws Exception{
        String shellDir = "";
        String shellPath = "";
        try {
            //获取脚本所在的目录
            String configFilePath = Thread.currentThread().getContextClassLoader().getResource("config.properties").getPath();
            File f = new File(configFilePath);
            shellDir = f.getParent();
            log.info("shell dir = " + shellDir);

            //拼接完整的脚本目录
            shellPath = shellDir + "/shell/" + shellName;
            log.info("shell path = " + shellPath);

            //执行脚本
            callScript(shellPath);

        } catch (Exception e) {
            log.error("ShellExcutor异常" + e.getMessage(), e);
            throw e;
        }
    }

    /**
     * 脚本文件具体执行及脚本执行过程探测
     * @param script 脚本文件绝对路径
     * @throws Exception
     */
    private void callScript(String script) throws Exception{
        try {
            String cmd = "sh " + script;

            //启动独立线程等待process执行完成
            CommandWaitForThread commandThread = new CommandWaitForThread(cmd);
            commandThread.start();

            while (!commandThread.isFinish()) {
                log.info("shell " + script + " 还未执行完毕,10s后重新探测");
                Thread.sleep(10000);
            }

            //检查脚本执行结果状态码
            if(commandThread.getExitValue() != 0){
                throw new Exception("shell " + script + "执行失败,exitValue = " + commandThread.getExitValue());
            }
            log.info("shell " + script + "执行成功,exitValue = " + commandThread.getExitValue());
        }
        catch (Exception e){
            throw new Exception("执行脚本发生异常,脚本路径" + script, e);
        }
    }

    /**
     * 脚本函数执行线程
     */
    public class CommandWaitForThread extends Thread {

        private String cmd;
        private boolean finish = false;
        private int exitValue = -1;

        public CommandWaitForThread(String cmd) {
            this.cmd = cmd;
        }

        public void run(){
            try {
                //执行脚本并等待脚本执行完成
                Process process = Runtime.getRuntime().exec(cmd);

                //写出脚本执行中的过程信息
                BufferedReader infoInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
                BufferedReader errorInput = new BufferedReader(new InputStreamReader(process.getErrorStream()));
                String line = "";
                while ((line = infoInput.readLine()) != null) {
                    log.info(line);
                }
                while ((line = errorInput.readLine()) != null) {
                    log.error(line);
                }
                infoInput.close();
                errorInput.close();

                //阻塞执行线程直至脚本执行完成后返回
                this.exitValue = process.waitFor();
            } catch (Throwable e) {
                log.error("CommandWaitForThread accure exception,shell " + cmd, e);
                exitValue = 110;
            } finally {
                finish = true;
            }
        }

        public boolean isFinish() {
            return finish;
        }

        public void setFinish(boolean finish) {
            this.finish = finish;
        }

        public int getExitValue() {
            return exitValue;
        }
    }
}

四、参考链接

https://blog.csdn.net/u010376788/article/details/51337312
https://yq.aliyun.com/articles/2362
https://blog.csdn.net/haiyang4988/article/details/75228416

猜你喜欢

转载自blog.csdn.net/tterminator/article/details/82227394
今日推荐