1、判斷子進程是否執行結束
有的時候我們用java調用shell之後,之後的操作要在Process子進程正常執行結束的情況下才可以繼續,所以我們需要判斷Process進程什麼時候終止。
Process類提供了waitFor()方法。該方法導致當前線程等待,直到Process線程終止。
Process.waitFor()是有一個int類型傳回值的,當傳回值為0的時候表Process進程正常終止。否則一般是指令碼執行出錯了(我遇到的一般是這種情況)。
2、Process.waitFor()導致當前線程阻塞。
有的時候我們發現調用waitFor()方法後,java主線程會一直阻塞在waitFor()處,阻塞的原因是什麼呢。分析一下:
Java在執行Runtime.getRuntime().exec(jyName)之後,Linux會建立一個進程,該進程與JVM進程建立三個管道串連,標準輸入資料流、標準輸出資料流、標準錯誤流,假設linux進程不斷
向標準輸出資料流和標準錯誤流寫資料,而JVM卻不讀取,資料會暫存在linux緩衝區,當緩衝區存滿之後導致該進程無法繼續寫資料,會僵死,導致java進程會卡死在waitFor()處,
永遠無法結束。
解決辦法:java進程在waitFor()前不斷讀取標準輸出資料流和標準錯誤流:
//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);//讀取標準輸出資料流BufferedReader bufferedReader =new BufferedReader(new InputStreamReader(p0.getInputStream()));String line;while ((line=bufferedReader.readLine()) != null) { System.out.println(line);}//讀取標準錯誤流BufferedReader brError = new BufferedReader(new InputStreamReader(p0.getErrorStream(), "gb2312"));String errline = null;while ((errline = brError.readLine()) != null) { System.out.println(errline);}//waitFor()判斷Process進程是否終止,通過傳回值判斷是否正常終止。0代表正常終止int c=p0.waitFor();if(c!=0){baseRes.put("desc", "軟體升級失敗:執行zxvf.sh異常終止");baseRes.setReturnFlag(false);return baseRes;}} catch (IOException e1) {baseRes.put("desc", "軟體升級失敗:檔案解壓失敗");baseRes.setReturnFlag(false);return baseRes;} catch (InterruptedException e1) {baseRes.put("desc", "軟體升級失敗:檔案解壓失敗");baseRes.setReturnFlag(false);return baseRes;}
也可以在執行Runtime.getRuntime().exec(jyName)之後另外再啟動兩個線程分別讀取標準錯誤流和標準輸出資料流
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;}@Overridepublic 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 blocke.printStackTrace();}}}};t1.start();t2.start();} catch (IOException e1) {// TODO Auto-generated catch blocke1.printStackTrace();} finally {}}}
3、shell指令碼中有關聯指令碼,注意路徑
就是shell指令碼中還要執行其他指令碼,這時候就是注意一個路徑的問題,這個問題也是我找了好長時間的一個問題。
Process p=Runtime.getRuntime().exec(“/etc/a.sh”)
在Test.java類調用了etc目錄下的a.sh指令碼, a.sh指令碼中執行etc目錄下的b.sh指令碼,原來我在a.sh指令碼中寫的是./b.sh。其實這樣linux是找不到b.sh的,因為我們執行是在
Test.class目錄下調用的/etc/a.sh 所以當a.sh中執行./b.sh的時候他會在Test.class目錄下尋找,所以找不到,所以a.sh中要寫成/etc/b.sh
4、java連續調用多個指令碼
String[] cmd = { "/bin/sh", "-c", "rm -rf /installation/upgrade/ ; mkdir /installation/upgrade/" };Process p = Runtime.getRuntime().exec(cmd);p.waitFor();
就是這種數組的方式。
5、java執行.sh指令檔的時候直接寫目錄就行,例如這樣:Runtime.getRuntime().exec(“/etc/a.sh”)
java 直接執行語句的時候需要加上"/bin/sh" 例如這樣:
String name="/bin/sh cd /installation/upgrade/ip89_install_packet";Process p = Runtime.getRuntime().exec(name);