1. 程式人生 > >java執行linux和windows指令碼工具類

java執行linux和windows指令碼工具類

我們有時候會

在java程式碼中,去執行一個linux shell指令碼或者windows觸發執行一個.bat指令碼

本文章,會寫一個通用的指令碼工具類,通過這個工具類,可以在java程式碼中,呼叫linux shell指令碼,或者window .bat指令碼。

比如我們資料平臺,有一個數據分析工具,當資料分析工程師,通過我們的工具,配置了某一個數據分析任務,後臺的injector程序會監測到這個job,然後會呼叫shell指令碼,去叢集上執行我們的MapReduce程式。

本工具類就是實現如何java中呼叫linux  shell指令碼的, 當然windows 也是支援的。

首先定義一下結果類:

public class CommandResult {
    public static final int EXIT_VALUE_TIMEOUT=-1;
    int exitValue;
    private String output;
    private String error;


    public int getExitValue() {
        return exitValue;
    }

    public void setExitValue(int exitValue) {
        this.exitValue = exitValue;
    }

    public String getOutput() {
        return output;
    }

    public void setOutput(String output) {
        this.output = output;
    }

    public String getError() {
        return error;
    }

    public void setError(String error) {
        this.error = error;
    }
}

接下來 ,寫我們 核心的CommandUtils工具類

public class CommandUtils {
    public static Logger logger = LoggerFactory.getLogger(CommandUtils.class);
    public static int DEFAULT_TIMEOUT=1000;
    public static final int DEFAULT_INTERVAL=100;
    public static long startTime ;
    public static CommandResult exec(String command){
        startTime = System.nanoTime();
        Process process=null;
        CommandResult commandResult =null;
        try {
            if (null == command || "".equals(command = command.trim())) {
                commandResult = new CommandResult() ;
                commandResult.setExitValue(1);
                commandResult.setError("command is not empty");
            }
            String[] cmd;
            String osName = System.getProperty("os.name");
            if (osName.startsWith("Windows")) {
                cmd = new String[3];
                if (osName.equals("Windows 95")) { // windows 95 only
                    cmd[0] = "command.com";
                } else {
                    cmd[0] = "cmd.exe";
                }
                cmd[1] = "/C";
                cmd[2] = command;
            } else if (osName.equals("Linux")) {  //linux
                cmd = new String[3];
                cmd[0] = "/bin/sh";
                cmd[1] = "-c";
                cmd[2] = command;
            } else {
                cmd = new String[1];
                cmd[0] = command;
            }
             process= Runtime.getRuntime().exec(cmd);
             commandResult = wait(process);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }finally {
            if (process!=null){
                process.destroy();
            }
            return commandResult;
        }
    }
//判斷是否超時
    public static  boolean isOverTime(){
        return  (TimeUnit.MILLISECONDS.toNanos(DEFAULT_TIMEOUT) - (System.nanoTime() - startTime)) < 0;
    }

    public static CommandResult wait(Process process) throws InterruptedException, IOException {
        BufferedReader errorStreamReader = null;
        BufferedReader inputStreamReader = null;
        try {
            errorStreamReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            inputStreamReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            boolean isFinished = false;
            while (true) {  //這是一個死迴圈,直到超時,或者command 執行完成
                if (isOverTime()) {  //如果超時 ,直接返回
                    CommandResult result = new CommandResult();
                    result.setExitValue(CommandResult.EXIT_VALUE_TIMEOUT);
                    result.setOutput("Command process timeout");
                    return result;
                }
                if (isFinished) {
                    CommandResult result = new CommandResult();
                    result.setExitValue(process.waitFor());
                    //  error info 
                    if (errorStreamReader.ready()) {  
                        StringBuilder buffer = new StringBuilder();
                        String line;
                        while ((line = errorStreamReader.readLine()) != null) {
                            buffer.append(line);
                        }
                        result.setError(buffer.toString());
                    }
                    //  info
                    if (inputStreamReader.ready()) {
                        StringBuilder buffer = new StringBuilder();
                        String line;
                        while ((line = inputStreamReader.readLine()) != null) {
                            buffer.append(line);
                        }
                        result.setOutput(buffer.toString());
                    }
                    return result;
                }
                try {
                    isFinished = true;     //很樂觀的認為command 已經執行完成了 ,將isFinished 賦值為true
                    process.exitValue();   //這個方法,command 沒有執行完成的時候會丟擲異常IllegalThreadStateException被catch捕獲,如果執行完成 則isFinished =true
                } catch (IllegalThreadStateException e) {
                    //  hasn't finished yet
                    isFinished = false;  //執行到這裡,說明command 沒有執行完成,那麼將isFinished 重新設定為false;
                    Thread.sleep(DEFAULT_INTERVAL);  //如果command 沒有執行完成,可以睡眠 DEFAULT_INTERVAL 
                }
            }
        } finally {
            if (errorStreamReader != null) {
                try {
                    errorStreamReader.close();
                } catch (IOException e) {
                }
            }
            if (inputStreamReader != null) {
                try {
                    inputStreamReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

最後是我們的命令執行呼叫類:

public class InvokeCommand {

    public static void main(String[] args) {
        String win = "C:\\Users\\zhang\\xxx.bat";
        String lin = "/user/run.sh";

        int timeout = Integer.parseInt("5000");
        CommandUtils.DEFAULT_TIMEOUT = timeout;
        CommandResult result = CommandUtils.exec(win);
        if (result != null)
        {
            if (result.getError()!=null) {
                System.out.println("Error:" + result.getError());
            }
            if (result.getOutput()!=null) {
                System.out.println("Output:" + result.getOutput());
            }
        }

    }
}

上面測試了一下,win平臺下的效果,結果發現.bat檔案可以正常呼叫,並返回結果。

xxx.bat檔案內容為: @echo hello boy!

下面為測試返回結果: