0


Java执行shell命令

Java执行shell命令


前言

java执行shell命令的方式有很多种,但是在应用的过程中,我们可能会遇上一些特殊的情况,导致执行脚本失败,不生效的场景。


一、案例

场景

  • java服务,如果需要服务自动重启。那么我们通过java执行shell命令,使用常用jdk的方法:Runtime.getRuntime().exec(command)的方式,重启服务,可能会导致重启失败。

原因

  • java执行本地命令启动的是一个子进程处理,默认情况下子进程与父进程I/O通过管道相连(ProcessBuilder.Redirect.PIPE)
  • 当服务执行自身重启命令时,父进程关闭导致管道连接中断,将导致子进程也崩溃,而无法完成后续启动

解决方案

  1. 设置子进程的I/O源或目标将与当前进程的相同,两者相互独立
  2. 设置子进程IO输出重定向到指定文件

这里我们采用第一种解决方案

ProcessBuilder pb = new ProcessBuilder("service","java-service","restart");
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
pb.redirectInput(ProcessBuilder.Redirect.INHERIT);
pb.start();

ProcessBuilder 也是J2SE1.5 就有了的类。此类用于创建操作系统进程,它提供一种启动和管理进程(也就是应用程序)的方法。在J2SE 1.5之前,都是由Process类处来实现进程的控制管理。

static ProcessBuilder.Redirect    DISCARD    
表示将丢弃子进程输出。
static ProcessBuilder.Redirect    INHERIT    
表示子进程I / O源或目标将与当前进程的相同。
static ProcessBuilder.Redirect    PIPE    
表示子进程I / O将通过管道连接到当前Java进程。

ProcessBuilder 可配置执行脚本的子进程I / O源或目标将与当前进程的相同。绑定之后,执行重启,就能成功,管道不会断开。

ProcessBuilder 可参考连接:
ProcessBuilder api
ProcessBuilder 中文文档

二、拓展

创建临时脚本,执行shell命令

<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.11.0</version></dependency>

可直接复制使用,注意引入maven包

public static String runAndResult(String cmd){
        StringBuilder sb = new StringBuilder();
        BufferedReader br = null;
        boolean execFlag = true;
        String uuid = UUID.randomUUID().toString().replace("-","");
        String tempFileName ="./temp"+ uuid +".sh";
        try {
            String osName = System.getProperty("os.name").toUpperCase(Locale.ENGLISH);if(osName.matches("^(?i)LINUX.*$")|| osName.contains("MAC")){
                FileWriter execute_fw = new FileWriter(tempFileName);
                BufferedWriter execute_bw=new BufferedWriter(execute_fw);
                execute_bw.write(cmd +"\n");
                execute_bw.close();
                execute_fw.close();
                String command ="bash "+ tempFileName;
                Process p = Runtime.getRuntime().exec(command);
                p.waitFor();
                br = new BufferedReader(new InputStreamReader(p.getInputStream()));
                String line;while((line = br.readLine())!= null){
                    sb.append(System.lineSeparator());
                    sb.append(line);}
                br.close();
                br = new BufferedReader(new InputStreamReader(p.getErrorStream()));while((line = br.readLine())!= null){
                    sb.append(System.lineSeparator());
                    sb.append(line);if(line.length()>0){
                        execFlag = false;}}
                br.close();if(execFlag){}else{
                    throw new RuntimeException(sb.toString());}}else{
                throw new RuntimeException("不支持的操作系统类型");}}catch(Exception e){
            log.error("执行失败",e);}finally {if(br != null){
                try {
                    br.close();}catch(IOException e){
                    log.error("io异常",e);}}
            FileUtils.deleteQuietly(new File(tempFileName));}return sb.toString();}

三、总结

实践是检验真理的唯一标准,工作生活中一定要多总结,记录。如果你觉得有用,点个赞吧。收藏一下也是不错的。

标签: java 开发语言 linux

本文转载自: https://blog.csdn.net/weixin_43480441/article/details/128469668
版权归原作者 ice&wind 所有, 如有侵权,请联系我们删除。

“Java执行shell命令”的评论:

还没有评论