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

本文介绍了如何在Java中执行shell脚本,包括通过Runtime创建process和使用ProcessBuilder的方式。同时,针对权限问题,提到了使用ProcessBuilder改变脚本执行权限的方法,并提供了Java执行shell脚本的完整代码示例。

一、背景

最近要下线一台历史遗留的物理机,在整理该机的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.youkuaiyun.com/u010376788/article/details/51337312
https://yq.aliyun.com/articles/2362
https://blog.youkuaiyun.com/haiyang4988/article/details/75228416

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值