java執行linux和windows指令碼工具類
阿新 • • 發佈:2018-12-12
我們有時候會
在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!
下面為測試返回結果: