zoukankan      html  css  js  c++  java
  • Java调用Shell问题整理

    背景

    java可以通过Runtime来调用其他进程,如cmd命令,shell文件或脚本等。

    基本用法

    Runtime执行时返回一个Process对象,利用该对象完成脚本执行。下面的例子中,Linux的/home/目录下有一个删除指定日期文件的脚本deletefile.sh,Java调用该脚本的方法如下。

     /**
         * 删除指定日期的文件
         * @param date  yyyy-MM-dd格式
         */
        private static  void setSystemDate(String date){
            Process process = null;
            String command1 = "/bin/sh /home/deletefile.sh "+date;
            System.out.println(command1);
            try {
                process = Runtime.getRuntime().exec(command1);
                //必须等待该进程结束,否则时间设置就无法生效
                process.waitFor();
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }finally{
                if(process!=null){
                    process.destroy();
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    缓冲区满问题

    如果脚本执行过程中产生大量的控制台输出信息,这种信息会被Shell进程输出到内存缓冲区中,而上述用法中作为父进程的java进程并没有处理缓冲区内容,那么就会出现缓冲区满,Java进程挂起的情况。
    解决办法是,使用Java线程读取Shell脚本的输出信息。

       public static List<String> executeShell(String shpath, String var){
            
            //String shpath="/test/test.sh";   // sh 路径
            //String var="201102";             // sh 参数
            String shellVar = (var==null)?"":var;
            String command1 = "chmod 777 " + shpath; // 为 sh 添加权限
            String command2 = "/bin/sh " + shpath + " " + shellVar; 
            final List<String> strList = new ArrayList<String>(); 
            Process process1 = null;
            BufferedReader in = null;
            try {
                process1 = Runtime.getRuntime().exec(command1); // 执行添加权限的命令
                process1.waitFor(); // 如果执行多个命令,必须加上
                final Process process2 = Runtime.getRuntime().exec(command2);
               
                //处理InputStream的线程  
                new Thread() {  
                    @Override  
                    public void run() {  
                        BufferedReader in = new BufferedReader(new InputStreamReader(process2.getInputStream()));   
                        String line = null;  
                        try{  
                            while((line = in.readLine()) != null) {  
                            	strList.add(line);
                            }  
                        }catch(IOException e) {                         
                            e.printStackTrace();  
                        }finally {  
                            try {  
                                in.close();  
                            }   
                            catch (IOException e) {  
                                e.printStackTrace();  
                            }  
                        }  
                    }  
                }.start();  
    
                //处理ErrorStream的线程  
                new Thread() {  
                    @Override  
                    public void run(){  
                        BufferedReader err = new BufferedReader(new InputStreamReader(process2.getErrorStream()));   
                        String line = null;  
                        try{  
                            while((line = err.readLine()) != null)  
                            {  
                            	strList.add(line); 
                            }  
                        }catch(IOException e){                         
                            e.printStackTrace();  
                        }finally{  
                            try{  
                                err.close();  
                            }catch (IOException e){  
                                e.printStackTrace();  
                            }  
                        }  
                    }  
                }.start(); 
                
                process2.waitFor();
     
            } catch (IOException e) {
    
            } catch (InterruptedException e) {
               
            }finally {
                if(in != null){
                    try {
                        in.close();
                    } catch (IOException e) {
     
                    }
                }
                if(process1 != null){
                    process1.destroy();
                }
            }
            return strList;
        }
    
    • 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
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    线程阻塞问题

    如果执行的shell脚本中有等待输入命令,比如more操作,那么在使用java进程读取缓冲区内容的时候,会出现线程阻塞等待的问题。
    例如,下面的脚本读取文件内容。

    filePath=/home/software.info
    softType=$(more $filePath)
    echo $softType
    
    • 1
    • 2
    • 3

    上述三行代码很简单地输出了一个文件的内容,而且这个文件很短,只有一行,在Linux下执行没有问题,但是如果用Java调用executeShell方法执行的话,处理InputStream的线程会出现阻塞等待问题,根源在于脚本中的more命令,它会等待控制台的输入,从而导致了Java进程的阻塞。
    解决办法就是避免在shell脚本中使用more命令,用cat命令替换即可。

    管道命令不执行问题

    使用Process执行shell命令时,如果命令中包含管道命令,直接执行会得不到正确结果,解决办法是使用/bin/sh,将/bin/sh放在待执行的shell命令的前面,可保证管道命令的正确执行。

    String command1 = "/bin/sh ifconfig | grep if= | awk '{print $1,$6}'";
    
    
    • 1
    • 2

    启示录

    究竟在Java中调用Shell是不是明智的呢?

  • 相关阅读:
    unity调用Android的两种方式:其二,调用aar包
    Unity调用Android的两种方式:其一、调用jar包
    使用 Gradle 编译 Java 项目时报错: Could not find Tools.jar
    Unity CommandInvokationFailure: Failed to re-package resources. 解决方案
    Unity Android路径及注意事项
    Unity Debug类
    Unity C#集合
    Unity C# const与static readonly的区别与联系
    Unity 脚本中各种[XXX]的用法
    unity 看到Sphere内部,通过Sphere播放全景视频时候遇到的问题
  • 原文地址:https://www.cnblogs.com/exmyth/p/13851083.html
Copyright © 2011-2022 走看看