Java調(diào)用shell命令涉及管道、重定向時(shí)不生效問(wèn)題及解決
Java調(diào)用shell命令涉及管道、重定向時(shí)不生效
近日,因項(xiàng)目需求需要用java調(diào)用shell命令實(shí)現(xiàn)清理過(guò)時(shí)圖片任務(wù),發(fā)現(xiàn)代碼生成出來(lái)的shell命令在linux系統(tǒng)后臺(tái)直接執(zhí)行,可以實(shí)現(xiàn)效果,但是,經(jīng)過(guò)java代碼運(yùn)行,則達(dá)不到預(yù)期效果。
經(jīng)研究發(fā)現(xiàn),因?yàn)樵搒hell命令涉及了管道,這情況就有點(diǎn)不一樣了,下面是針對(duì)Java調(diào)用shell命令涉及管道、重定向時(shí)不生效問(wèn)題的解決方法
參考代碼如下:
public class Test { /** * @param args * @throws IOException * @throws InterruptedException */ public static void main(String[] args) throws IOException, InterruptedException { Process p; String command = "find /opt/Img/ \"2019-11-22-*.jpg\" | xargs rm -rf"}; // 必須加上sh -c p = Runtime.getRuntime().exec(new String[]{"sh","-c",command}); if(0==p.waitFor()) { System.out.println("Command execute result is OK!"); } else { System.out.println("Command execute result is fail......"); } } }
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)前線程等待,直到Process線程終止。
Process.waitFor()是有一個(gè)int類(lèi)型返回值的,當(dāng)返回值為0的時(shí)候表Process進(jìn)程正常終止。否則一般是腳本執(zhí)行出錯(cuò)了(我遇到的一般是這種情況)。
2、Process.waitFor()導(dǎo)致當(dāng)前線程阻塞
有的時(shí)候我們發(fā)現(xiàn)調(diào)用waitFor()方法后,java主線程會(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ū)存滿之后導(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è)線程分別讀取標(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);
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
eclipse創(chuàng)建多層包(多級(jí)包)全過(guò)程
這篇文章主要介紹了eclipse創(chuàng)建多層包(多級(jí)包)全過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11Java8新特性之接口中的默認(rèn)方法和靜態(tài)方法詳解
今天帶大家學(xué)習(xí)的是Java8新特性的相關(guān)知識(shí),文章圍繞著Java接口中的默認(rèn)方法和靜態(tài)方法展開(kāi),文中有非常詳細(xì)的的代碼示例,需要的朋友可以參考下2021-06-06Spring Boot + Thymeleaf + Activiti 快速開(kāi)發(fā)平臺(tái)項(xiàng)目 附源碼
這篇文章主要介紹了Spring Boot + Thymeleaf + Activiti 快速開(kāi)發(fā)平臺(tái)項(xiàng)目附源碼,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04詳解IDEA中類(lèi)加載器調(diào)用getResourceAsStream()方法需注意的問(wèn)題
這篇文章主要介紹了詳解IDEA中類(lèi)加載器調(diào)用getResourceAsStream()方法需注意的問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02一個(gè)applicationContext 加載錯(cuò)誤導(dǎo)致的阻塞問(wèn)題及解決方法
這篇文章主要介紹了一個(gè)applicationContext 加載錯(cuò)誤導(dǎo)致的阻塞問(wèn)題及解決方法,需要的朋友可以參考下2018-11-11Java實(shí)現(xiàn)拖拽文件上傳dropzone.js的簡(jiǎn)單使用示例代碼
本篇文章主要介紹了Java實(shí)現(xiàn)拖拽文件上傳dropzone.js的簡(jiǎn)單使用示例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下2017-07-07性能爆棚的實(shí)體轉(zhuǎn)換復(fù)制工具M(jìn)apStruct使用詳解
這篇文章主要為大家介紹了性能爆棚的實(shí)體轉(zhuǎn)換復(fù)制工具M(jìn)apStruct使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03java遞歸與非遞歸實(shí)現(xiàn)掃描文件夾下所有文件
這篇文章主要為大家詳細(xì)介紹了java遞歸與非遞歸實(shí)現(xiàn)掃描文件夾下所有文件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-02-02