Java中如何執(zhí)行多條shell/bat命令
java調(diào)用process執(zhí)行命令
public class ShellUtil { public static String runShell (String shStr) throws Exception { Process process; process = Runtime.getRuntime().exec( new String[]{ "/bin/sh" , "-c" ,shStr}); process.waitFor(); BufferedReader read = new BufferedReader( new InputStreamReader(process.getInputStream())); String line = null ; String result = "" ; while ((line = read.readLine())!= null ){ result+=line; } return result; } }
注意:如果是windows操作系統(tǒng)要改為
Runtime.getRuntime().exec(new String[]{"**cmd** exe","-c","command"});
1.當(dāng)要執(zhí)行多條時(shí)且不依賴(lài)事務(wù),可以分開(kāi)多次調(diào)用
public class ExecuteShell { public static void main (String[] args){ String command1 = "some command" ; String command2 = "some command" ; String message1 = ShellUtil.runShell(command1); String message2 = ShellUtil.runShell(command2); System. out .println(message1); System. out .println(message2); } }
2.但是當(dāng)命令之間有事務(wù)依賴(lài)時(shí)
比如一條命令是登錄數(shù)據(jù)庫(kù),第二條執(zhí)行查詢(xún)語(yǔ)句,上面分開(kāi)多次調(diào)用的方式就不行。需要做改動(dòng)如下
public class ExecuteShell { public static void main (String[] args){ String command1 = "some command" ; String command2 = "some command" ; String command = command1 + " && " + command2; String message = ShellUtil.runShell(command); System. out .println(message); } }
Java執(zhí)行shell遇到的各種問(wèn)題
1、判斷子進(jìn)程是否執(zhí)行結(jié)束
有的時(shí)候我們用java調(diào)用shell之后,之后的操作要在Process子進(jìn)程正常執(zhí)行結(jié)束的情況下才可以繼續(xù),所以我們需要判斷Process進(jìn)程什么時(shí)候終止。
Process類(lèi)提供了waitFor()方法。該方法導(dǎo)致當(dāng)前線(xiàn)程等待,直到Process線(xiàn)程終止。
Process.waitFor()是有一個(gè)int類(lèi)型返回值的,當(dāng)返回值為0的時(shí)候表Process進(jìn)程正常終止。否則一般是腳本執(zhí)行出錯(cuò)了(我遇到的一般是這種情況)。
2、Process.waitFor()導(dǎo)致當(dāng)前線(xiàn)程阻塞
有的時(shí)候我們發(fā)現(xiàn)調(diào)用waitFor()方法后,java主線(xiàn)程會(huì)一直阻塞在waitFor()處,阻塞的原因是什么呢?
分析一下:
Java在執(zhí)行Runtime.getRuntime().exec(jyName)之后,Linux會(huì)創(chuàng)建一個(gè)進(jìn)程,該進(jìn)程與JVM進(jìn)程建立三個(gè)管道連接,標(biāo)準(zhǔn)輸入流、標(biāo)準(zhǔn)輸出流、標(biāo)準(zhǔn)錯(cuò)誤流,假設(shè)linux進(jìn)程不斷向標(biāo)準(zhǔn)輸出流和標(biāo)準(zhǔn)錯(cuò)誤流寫(xiě)數(shù)據(jù),而JVM卻不讀取,數(shù)據(jù)會(huì)暫存在linux緩存區(qū),當(dāng)緩存區(qū)存滿(mǎn)之后導(dǎo)致該進(jìn)程無(wú)法繼續(xù)寫(xiě)數(shù)據(jù),會(huì)僵死,導(dǎo)致java進(jìn)程會(huì)卡死在waitFor()處,永遠(yuǎn)無(wú)法結(jié)束。
解決辦法:
java進(jìn)程在waitFor()前不斷讀取標(biāo)準(zhǔn)輸出流和標(biāo)準(zhǔn)錯(cuò)誤流:
//jyName 解壓腳本路徑 String fileName=fileList.get(0).toString().substring(fileList.get(0).toString().lastIndexOf(File.separator)+1); String jyName="/etc/zxvf.sh "+fileName; try { Process p0 = Runtime.getRuntime().exec(jyName); //讀取標(biāo)準(zhǔn)輸出流 BufferedReader bufferedReader =new BufferedReader(new InputStreamReader(p0.getInputStream())); String line; while ((line=bufferedReader.readLine()) != null) { System.out.println(line); } //讀取標(biāo)準(zhǔn)錯(cuò)誤流 BufferedReader brError = new BufferedReader(new InputStreamReader(p0.getErrorStream(), "gb2312")); String errline = null; while ((errline = brError.readLine()) != null) { System.out.println(errline); } //waitFor()判斷Process進(jìn)程是否終止,通過(guò)返回值判斷是否正常終止。0代表正常終止 int c=p0.waitFor(); if(c!=0){ baseRes.put("desc", "軟件升級(jí)失敗:執(zhí)行zxvf.sh異常終止"); baseRes.setReturnFlag(false); return baseRes; } } catch (IOException e1) { baseRes.put("desc", "軟件升級(jí)失?。何募鈮菏?); baseRes.setReturnFlag(false); return baseRes; } catch (InterruptedException e1) { baseRes.put("desc", "軟件升級(jí)失?。何募鈮菏?); baseRes.setReturnFlag(false); return baseRes; }
也可以在執(zhí)行Runtime.getRuntime().exec(jyName)之后另外再啟動(dòng)兩個(gè)線(xiàn)程分別讀取標(biāo)準(zhǔn)錯(cuò)誤流和標(biāo)準(zhǔn)輸出流
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; public class ExcuteThread extends Thread { private String name; public ExcuteThread(String name) { this.name = name; } @Override public void run() { try { Process p = Runtime.getRuntime().exec(name); InputStream fis = p.getInputStream(); final BufferedReader brError = new BufferedReader( new InputStreamReader(p.getErrorStream(), "gb2312")); InputStreamReader isr = new InputStreamReader(fis, "gb2312"); final BufferedReader br = new BufferedReader(isr); Thread t1 = new Thread() { public void run() { String line = null; try { while ((line = brError.readLine()) != null) { // System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (brError != null) brError.close(); } catch (IOException e) { e.printStackTrace(); } } } }; Thread t2 = new Thread() { public void run() { String line = null; try { while ((line = br.readLine()) != null) { // System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (br != null) br.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }; t1.start(); t2.start(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } finally { } } }
3、shell腳本中有關(guān)聯(lián)腳本,注意路徑
就是shell腳本中還要執(zhí)行其他腳本,這時(shí)候就是注意一個(gè)路徑的問(wèn)題,這個(gè)問(wèn)題也是我找了好長(zhǎng)時(shí)間的一個(gè)問(wèn)題。
Process p=Runtime.getRuntime().exec(“/etc/a.sh”)
在Test.java類(lèi)調(diào)用了etc目錄下的a.sh腳本, a.sh腳本中執(zhí)行etc目錄下的b.sh腳本,原來(lái)我在a.sh腳本中寫(xiě)的是./b.sh。
其實(shí)這樣linux是找不到b.sh的,因?yàn)槲覀儓?zhí)行是在Test.class目錄下調(diào)用的/etc/a.sh 所以當(dāng)a.sh中執(zhí)行./b.sh的時(shí)候他會(huì)在Test.class目錄下尋找,所以找不到,所以a.sh中要寫(xiě)成/etc/b.sh
4、java連續(xù)調(diào)用多個(gè)腳本
String[] cmd = { "/bin/sh", "-c", "rm -rf /installation/upgrade/ ; mkdir /installation/upgrade/" }; Process p = Runtime.getRuntime().exec(cmd); p.waitFor();
就是這種數(shù)組的方式。
5、java執(zhí)行.sh腳本文件的時(shí)候直接寫(xiě)目錄就行
例如這樣:
Runtime.getRuntime().exec(“/etc/a.sh”)
java 直接執(zhí)行語(yǔ)句的時(shí)候需要加上"/bin/sh" 例如這樣:
String name="/bin/sh cd /installation/upgrade/ip89_install_packet"; Process p = Runtime.getRuntime().exec(name);
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot引入Thymeleaf的實(shí)現(xiàn)方法
這篇文章主要介紹了SpringBoot引入Thymeleaf的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04Springcloud實(shí)現(xiàn)服務(wù)多版本控制的示例代碼
這篇文章主要介紹了Springcloud實(shí)現(xiàn)服務(wù)多版本控制的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05Java基于虹軟實(shí)現(xiàn)人臉識(shí)別、人臉比對(duì)、活性檢測(cè)等
本文主要介紹了Java基于虹軟實(shí)現(xiàn)人臉識(shí)別、人臉比對(duì)、活性檢測(cè)等,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02SpringBoot利用自定義注解實(shí)現(xiàn)隱私數(shù)據(jù)脫敏(加密顯示)的解決方案
這兩天在整改等保測(cè)出的問(wèn)題,里面有一個(gè)“用戶(hù)信息泄露”的風(fēng)險(xiǎn)項(xiàng)(就是后臺(tái)系統(tǒng)里用戶(hù)的一些隱私數(shù)據(jù)直接明文顯示了),其實(shí)指的就是要做數(shù)據(jù)脫敏,本文給大家介紹了SpringBoot利用自定義注解實(shí)現(xiàn)隱私數(shù)據(jù)脫敏(加密顯示)的解決方案,需要的朋友可以參考下2023-11-11如何解決SpringBoot2.x版本對(duì)Velocity模板不支持的方案
這篇文章主要介紹了如何解決SpringBoot2.x版本對(duì)Velocity模板不支持的方案,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12淺析java volatitle 多線(xiàn)程問(wèn)題
Volatile修飾的成員變量在每次被線(xiàn)程訪(fǎng)問(wèn)時(shí),都強(qiáng)迫從共享內(nèi)存中重讀該成員變量的值。而且,當(dāng)成員變量發(fā)生變化時(shí),強(qiáng)迫線(xiàn)程將變化值回寫(xiě)到共享內(nèi)存2013-08-08Mybatis調(diào)用SQL?Server存儲(chǔ)過(guò)程的實(shí)現(xiàn)示例
在軟件開(kāi)發(fā)過(guò)程中,經(jīng)常會(huì)使用到存儲(chǔ)過(guò)程,本文就來(lái)介紹一下Mybatis調(diào)用SQL?Server存儲(chǔ)過(guò)程的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01