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

 更新时间:2021年08月11日 08:41:35   作者:qq342643414  
这篇文章主要介绍了Java中如何执行多条shell/bat命令的方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

java调用process执行命令

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操作系统要改为

Runtime.getRuntime().exec(new String[]{"**cmd** exe","-c","command"});

1.当要执行多条时且不依赖事务,可以分开多次调用

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.但是当命令之间有事务依赖时

比如一条命令是登录数据库,第二条执行查询语句,上面分开多次调用的方式就不行。需要做改动如下

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()前不断读取标准输出流和标准错误流:

 //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;
 }
 @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脚本中还要执行其他脚本,这时候就是注意一个路径的问题,这个问题也是我找了好长时间的一个问题。

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);

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java的函数式编程详解

    Java的函数式编程详解

    用了这么久的Java8,我寻思这种话也好意思说出来吗,难道自己是PythonBoy出身就是看不懂Java的理由吗,身为一个合格的后端Boy不会还有人看不明白Java的函数式编程吧,接下来小编和大家浅聊一下Java的函数式编程,需要的朋友可以参考下
    2023-10-10
  • Java日期时间及日期相互转换实现代码

    Java日期时间及日期相互转换实现代码

    这篇文章主要介绍了Java日期时间及日期相互转换实现代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • Java文件处理之使用itextpdf实现excel转pdf

    Java文件处理之使用itextpdf实现excel转pdf

    在文件处理中,经常有文件类型转换的使用场景,本文主要介绍了如何使用poi以及itextpdf完成excel转pdf的操作,需要的小伙伴可以参考一下
    2024-02-02
  • 使用原生JDBC动态解析并获取表格列名和数据的方法

    使用原生JDBC动态解析并获取表格列名和数据的方法

    这篇文章主要介绍了使用原生JDBC动态解析并获取表格列名和数据,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-08-08
  • Mybatis结果生成键值对的实例代码

    Mybatis结果生成键值对的实例代码

    这篇文章主要介绍了Mybatis结果生成键值对的实例代码,以及MyBatis返回Map键值对数据的实现方法,非常不错,具有参考借鉴价值,需要的的朋友参考下
    2017-02-02
  • Java中Map遍历的九种方式汇总

    Java中Map遍历的九种方式汇总

    这篇文章主要介绍了Java中九种 Map 的遍历方式汇总的相关资料,需要的朋友可以参考下
    2022-11-11
  • springboot 如何使用jackson来处理实体类

    springboot 如何使用jackson来处理实体类

    这篇文章主要介绍了springboot使用jackson来处理实体类的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • 在SpringBoot中配置日期格式化的方法详解

    在SpringBoot中配置日期格式化的方法详解

    通常情况下,发起一个 Http 请求,Spring Boot 会根据请求路径映射到指定 Controller 上的某个方法的参数上,接着,Spring 会自动进行类型转换,对于日期类型的参数,Spring 默认是没有配置如何将字符串转换成日期类型的,本文将给大家介绍在SpringBoot中配置日期格式化的方法
    2023-10-10
  • Springcloud微服务架构基础知识解析

    Springcloud微服务架构基础知识解析

    这篇文章主要介绍了Springcloud微服务架构基础知识解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • Java面试题冲刺第二十八天--数据库(5)

    Java面试题冲刺第二十八天--数据库(5)

    这篇文章主要为大家分享了最有价值的三道关于数据库的面试题,涵盖内容全面,包括数据结构和算法相关的题目、经典面试编程题等,感兴趣的小伙伴们可以参考一下
    2021-09-09

最新评论