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