Java 學習筆記(三)呼叫 bat 或 shell 指令碼執行
阿新 • • 發佈:2020-09-17
一、背景
在某些程式中需要 Java 程式碼直接 呼叫 bat 指令碼或 sh 指令碼 執行,但是除了命令不一樣以外,所有的邏輯是一樣的,為此以下給出通用程式碼。
二、示例 + 說明
package com.example.demo.tool; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import org.apache.commons.lang3.StringUtils;import com.example.demo.test.StreamManage; import com.google.common.base.Joiner; import com.google.common.base.Splitter; import lombok.extern.slf4j.Slf4j; @Slf4j public class CmdUtils { private static AtomicBoolean error = new AtomicBoolean(false); /* * 啟動程式 */ public static synchronizedboolean startApp(String appParentAbsolute) { String osName = System.getProperty("os.name"); String[] cmds = null; try { if (osName.toLowerCase().contains("windows")) { // windows 平臺 cmds = new String[] { "cd /d \"" + appParentAbsolute + File.separator + "script" + "\"","start.bat>start.log" }; // 多條命令 exec4Windows(cmds); } else if (osName.toLowerCase().contains("linux")) { // linux平臺 cmds = new String[] { "cd \"" + appParentAbsolute + File.separator + "script" + "\"", "./start.sh>start.log" }; // 多條命令 exec4Linux(cmds); } return true; } catch (IOException e) { log.error("start app fail", e); } catch (InterruptedException e) { log.error("start app fail", e); } catch (IllegalAccessError e) { log.error("start app fail", e); } return false; } /* * 停止程式 */ public static synchronized boolean stopApp(String appParentAbsolute) { String osName = System.getProperty("os.name"); String[] cmds = null; try { if (osName.toLowerCase().contains("windows")) { // windows 平臺 cmds = new String[] { "cd /d \"" + appParentAbsolute + File.separator + "script" + "\"", "start /b stop.bat>stop.log" }; exec4Windows(cmds); // 多條命令 } else if (osName.toLowerCase().contains("linux")) { // linux平臺 cmds = new String[] { "cd \"" + appParentAbsolute + File.separator + "script" + "\"", "./stop.sh>stop.log" }; // 多條命令 exec4Linux(cmds); } return true; } catch (IOException e) { log.error("stop app fail", e); } catch (InterruptedException e) { log.error("stop app fail", e); } catch (IllegalAccessError e) { log.error("stop app fail", e); } return false; } private static String exec4Windows(String[] commands) throws IOException, InterruptedException { String cmd = Joiner.on("&&").join(commands); log.info("exec cmd : {}", cmd); return exec("cmd /c " + cmd); // 注意這裡 將多條 windows 命令使用 && 進行拼接形成字串,同時 在拼接字串開頭使用 cmd /c } private static String exec4Linux(String[] commands) throws IOException, InterruptedException { String cmd = Joiner.on("&&").join(commands); log.info("exec cmd : {}", cmd); return exec(new String[]{"/bin/bash","-c",cmd}); // 注意這裡 將多條 linux 命令使用 && 進行拼接形成字串,但是這裡沒有在拼接的字串開頭加上 /bin/bash -c
經過驗證直接 同windows一樣拼接字串去執行時不可行的, 只能作為一個 字串陣列 呼叫 Runtime.getRuntime().exec(String[])方法進行執行 } private static String exec(String[] commandArray) throws IOException, InterruptedException { Process process;// Process可以控制該子程序的執行或獲取該子程序的資訊 log.info("exec cmd : {}", Joiner.on(" ").join(commandArray)); process = Runtime.getRuntime().exec(commandArray);// exec()方法指示Java虛擬機器建立一個子程序執行指定的可執行程式,並返回與該子程序對應的Process物件例項。 return execBase(process); } private static String exec(String commands) throws IOException, InterruptedException { Process process;// Process可以控制該子程序的執行或獲取該子程序的資訊 log.info("exec cmd : {}", commands); process = Runtime.getRuntime().exec(commands);// exec()方法指示Java虛擬機器建立一個子程序執行指定的可執行程式,並返回與該子程序對應的Process物件例項。 return execBase(process); } private static String execBase(Process process) throws IOException, InterruptedException { // 下面兩個可以獲取輸入輸出流 InputStream errorStream = process.getErrorStream(); InputStream inputStream = process.getInputStream(); String result = StringUtils.EMPTY; StreamManage stream = new StreamManage(inputStream, "normal"); StreamManage errorStreamThread = new StreamManage(errorStream, "Error"); stream.setName("normal"); stream.start(); errorStreamThread.setName("Error"); errorStreamThread.start(); int exitStatus = 0; exitStatus = process.waitFor();// 等待子程序完成再往下執行,返回值是子執行緒執行完畢的返回值 // 第二種接受返回值的方法 int i = process.exitValue(); // 接收執行完畢的返回值 log.debug("i----" + i); if (exitStatus != 0) { log.error("exec cmd exitStatus {}", exitStatus); } else { log.debug("exec cmd exitStatus {}", exitStatus); } errorStreamThread.setEnd(true); stream.setEnd(true); process.destroy(); // 銷燬子程序 process = null; if (exitStatus != 0 || StringUtils.isNotEmpty(errorStreamThread.getResult())) { result = errorStreamThread.getResult(); throw new IllegalAccessError("exe fail,message:" + result); } else if (StringUtils.isNotEmpty(stream.getResult())) { result = stream.getResult(); } return result; } }
接收返回的資料流
package com.example.demo.test; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.Charset; import lombok.extern.slf4j.Slf4j; @Slf4j public class StreamManage extends Thread{ private InputStream inputStream; private String type; private String result; boolean end = false; //StreamManage的構造引數是InputStream類例項 => 實際上是Process例項的返回流 public StreamManage(InputStream inputStream,String type){ this.inputStream = inputStream; this.type = type; this.end = false; } public void run(){ log.info("start thread to read cmd "); InputStreamReader inputStreamReader = new InputStreamReader(inputStream,Charset.forName("GBK")); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String line = null; StringBuffer resultBuffer = new StringBuffer(); try{ while(!end){ if((line = bufferedReader.readLine())!=null){ if (type.equals("Error")) { log.error(line); }else{ log.debug(line); } resultBuffer.append(line); resultBuffer.append("\r\n"); } } log.info("result:[{}]", resultBuffer.toString()); result = resultBuffer.toString(); }catch (IOException e){ //ignore }catch(Throwable e){ log.warn("cmd fail.",e); }finally{ end = true; } } public String getResult() { return result; } public boolean isEnd() { return end; } public void setEnd(boolean end) { this.end = end; } }
這裡需要強調的是:
通過 Runtime.getRuntime().exec() 直接執行 Linux 命令 或呼叫 Linux 指令碼的時候,只能使用 通過方法 Runtime.getRuntime().exec(new String[]{"/bin/bash","-c",commond}) 方法,否則執行不了。