java調用process執行命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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操作系統要改為
1
|
Runtime.getRuntime().exec( new String[]{ "**cmd** exe" , "-c" , "command" }); |
1.當要執行多條時且不依賴事務,可以分開多次調用
1
2
3
4
5
6
7
8
9
10
|
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.但是當命令之間有事務依賴時
比如一條命令是登錄數據庫,第二條執行查詢語句,上面分開多次調用的方式就不行。需要做改動如下
1
2
3
4
5
6
7
8
9
|
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執行shell遇到的各種問題
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()前不斷讀取標準輸出流和標準錯誤流:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
//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)之后另外再啟動兩個線程分別讀取標準錯誤流和標準輸出流
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
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腳本中有關聯腳本,注意路徑
就是shell腳本中還要執行其他腳本,這時候就是注意一個路徑的問題,這個問題也是我找了好長時間的一個問題。
1
|
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連續調用多個腳本
1
2
3
|
String[] cmd = { "/bin/sh" , "-c" , "rm -rf /installation/upgrade/ ; mkdir /installation/upgrade/" }; Process p = Runtime.getRuntime().exec(cmd); p.waitFor(); |
就是這種數組的方式。
5、java執行.sh腳本文件的時候直接寫目錄就行
例如這樣:
1
|
Runtime.getRuntime().exec(“/etc/a.sh”) |
java 直接執行語句的時候需要加上"/bin/sh" 例如這樣:
1
2
|
String name= "/bin/sh cd /installation/upgrade/ip89_install_packet" ; Process p = Runtime.getRuntime().exec(name); |
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。
原文鏈接:https://blog.csdn.net/qq342643414/article/details/77880692