Java執(zhí)行shell命令的實現(xiàn)
前言
java執(zhí)行shell命令的方式有很多種,但是在應用的過程中,我們可能會遇上一些特殊的情況,導致執(zhí)行腳本失敗,不生效的場景。
一、案例
場景
java服務,如果需要服務自動重啟。那么我們通過java執(zhí)行shell命令,使用常用jdk的方法:Runtime.getRuntime().exec(command)的方式,重啟服務,可能會導致重啟失敗。
原因
- java執(zhí)行本地命令啟動的是一個子進程處理,默認情況下子進程與父進程I/O通過管道相連(ProcessBuilder.Redirect.PIPE)
- 當服務執(zhí)行自身重啟命令時,父進程關閉導致管道連接中斷,將導致子進程也崩潰,而無法完成后續(xù)啟動
解決方案
- 設置子進程的I/O源或目標將與當前進程的相同,兩者相互獨立
- 設置子進程IO輸出重定向到指定文件
這里我們采用第一種解決方案
ProcessBuilder pb = new ProcessBuilder("service","java-service","restart");
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
pb.redirectInput(ProcessBuilder.Redirect.INHERIT);
pb.start();
ProcessBuilder 也是J2SE1.5 就有了的類。此類用于創(chuàng)建操作系統(tǒng)進程,它提供一種啟動和管理進程(也就是應用程序)的方法。在J2SE 1.5之前,都是由Process類處來實現(xiàn)進程的控制管理。
static ProcessBuilder.Redirect DISCARD 表示將丟棄子進程輸出。 static ProcessBuilder.Redirect INHERIT 表示子進程I / O源或目標將與當前進程的相同。 static ProcessBuilder.Redirect PIPE 表示子進程I / O將通過管道連接到當前Java進程。
ProcessBuilder 可配置執(zhí)行腳本的子進程I / O源或目標將與當前進程的相同。綁定之后,執(zhí)行重啟,就能成功,管道不會斷開。
ProcessBuilder 可參考連接:
ProcessBuilder api
ProcessBuilder 中文文檔
二、拓展
創(chuàng)建臨時腳本,執(zhí)行shell命令
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
可直接復制使用,注意引入maven包
public static String runAndResult(String cmd){
StringBuilder sb = new StringBuilder();
BufferedReader br = null;
boolean execFlag = true;
String uuid = UUID.randomUUID().toString().replace("-","");
String tempFileName = "./temp" + uuid +".sh";
try {
String osName = System.getProperty("os.name").toUpperCase(Locale.ENGLISH);
if (osName.matches("^(?i)LINUX.*$") || osName.contains("MAC")) {
FileWriter execute_fw = new FileWriter(tempFileName);
BufferedWriter execute_bw=new BufferedWriter(execute_fw);
execute_bw.write(cmd + "\n");
execute_bw.close();
execute_fw.close();
String command ="bash " + tempFileName;
Process p = Runtime.getRuntime().exec(command);
p.waitFor();
br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = br.readLine()) != null) {
sb.append(System.lineSeparator());
sb.append(line);
}
br.close();
br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((line = br.readLine()) != null) {
sb.append(System.lineSeparator());
sb.append(line);
if (line.length() > 0){
execFlag = false;
}
}
br.close();
if (execFlag){
}else {
throw new RuntimeException(sb.toString());
}
}else {
throw new RuntimeException("不支持的操作系統(tǒng)類型");
}
} catch (Exception e) {
log.error("執(zhí)行失敗",e);
}finally {
if (br != null){
try {
br.close();
} catch (IOException e) {
log.error("io異常",e);
}
}
FileUtils.deleteQuietly(new File(tempFileName));
}
return sb.toString();
}
三、總結
實踐是檢驗真理的唯一標準,工作生活中一定要多總結,記錄。如果你覺得有用,點個贊吧。收藏一下也是不錯的。
到此這篇關于Java執(zhí)行shell命令的實現(xiàn)的文章就介紹到這了,更多相關Java執(zhí)行shell內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
windows定時器配置執(zhí)行java jar文件的方法詳解
這篇文章主要給大家介紹了關于windows定時器配置執(zhí)行java jar文件的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-11-11
SpringBoot3中Spring?WebFlux?SSE服務器發(fā)送事件的實現(xiàn)步驟
本文介紹了如何使用SpringBoot3和響應式編程實現(xiàn)服務器發(fā)送事件(SSE),并討論了其在實時數(shù)據(jù)推送場景中的優(yōu)勢,通過示例代碼,展示了如何創(chuàng)建SSE控制器、客戶端接收數(shù)據(jù)以及優(yōu)化與擴展,感興趣的朋友跟隨小編一起看看吧2024-11-11
Spring MVC返回的json去除根節(jié)點名稱的方法
這篇文章主要介紹了Spring MVC返回的json去除根節(jié)點名稱的方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-09-09

