好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Java中如何执行多条shell/bat命令

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

查看更多关于Java中如何执行多条shell/bat命令的详细内容...

  阅读:61次