转载

java操作Linux 调用shell命令,shell脚本

在最近做的项目当中,需要用 Java调用基于python写的两个不同的模型运行 并且得到实验结果:

1.在服务器上运行的文本识别模型

2.在本地Ubuntu中annacoda 虚拟环境中运行的影像识别模型

由于两个模型都是在终端执行,于是考虑用java代码直接调起终端,然后让终端执行指定的shell命令,测试代码如第二节;

由于模型的启动模型在不同的项目路径下,这种情况下指令需要好几条,有点繁琐,于是写了一个脚本,考虑用java直接调用shell脚本;

2.java调用shell命令

1.在实际项目当中,如果指令比较简单,可以直接把需要执行的指令传到Runtime.getRuntime().exec()中的参数。百度之后发现exec()有如下几种参数:

cmdarray: 包含所调用命令及其参数的数组。

command: 一条指定的系统命令。

envp: 字符串数组,其中每个元素的环境变量的设置格式为name=value;如果子进程应该继承当前进程的环境,则该参数为 null。

dir: 子进程的工作目录;如果子进程应该继承当前进程的工作目录,则该参数为 null。

Process exec(String command)   
在单独的进程中执行指定的字符串命令。   
 
Process exec(String[] cmdarray)   
在单独的进程中执行指定命令和变量。   
 
--不指定环境即默认环境
 
Process exec(String[] cmdarray, String[] envp)   
在指定环境的独立进程中执行指定命令和变量。   
 
Process exec(String[] cmdarray, String[] envp, File dir)   
在指定环境和工作目录的独立进程中执行指定的命令和变量。   
 
Process exec(String command, String[] envp)   
在指定环境的单独进程中执行指定的字符串命令。   
 
Process exec(String command, String[] envp, File dir)   
在有指定环境和工作目录的独立进程中执行指定的字符串命令。

复制代码

添加依赖包:

<dependency>
            <groupId>com.jcraft</groupId>
            <artifactId>jsch</artifactId>
            <version>0.1.50</version>
        </dependency>
复制代码

代码:ls;pwd

public void runPicmodels() {
      try {
           String shpath = "/home/hzhao/project_bj";
          String[] params = new String[] { "/bin/sh", "-c", "ls;pwd"};
          Process ps=Runtime.getRuntime().exec(params);
          ps.waitFor();

          BufferedReader bufrIn = new BufferedReader(new InputStreamReader(ps.getInputStream(), "UTF-8"));
          BufferedReader bufrError = new BufferedReader(new InputStreamReader(ps.getErrorStream(), "UTF-8"));

           // 读取输出 result是shell中的输出
          StringBuilder result = new StringBuilder();
          String line = null;
          while ((line = bufrIn.readLine()) != null || (line = bufrError.readLine()) != null) {
              result.append(line).append('/n');
          }

          System.out.println(result);
       } catch (Exception e) {
           e.printStackTrace();
       }
   }
复制代码

需要注意的是,在调用时需要执行waitFor()函数,因为shell进程是JAVA进程的子进程,JAVA作为父进程需要等待子进程执行完毕。

3.java调用shell脚本

1.写shell脚本---测试脚本

#!/usr/bin/sh
python /home/hzhao/sys.py
source activate zh_py35
cd /home/hzhao/project_bj/detection_pub
pwd
python /home/hzhao/sys.py
echo ------running-------
python __main__.pyc
echo ------success-------

复制代码

2.调用shell脚本:exec函数,参数编程shell文件,可以添加参数;

import java.io.BufferedReader; 
import java.io.InputStreamReader; 
  
public class RunShell { 
  public static void main(String[] args){ 
    try { 
      String shpath="/home/hzhao/Project/note.sh"; 
      Process ps = Runtime.getRuntime().exec(shpath); 
      ps.waitFor(); 
  
      BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream())); 
      StringBuffer sb = new StringBuffer(); 
      String line; 
      while ((line = brreadLine()) != null) { 
        sb.append(line).append("/n"); 
      } 
      String result = sbtoString(); 
      System.out.println(result); 
      }  
    catch (Exception e) { 
      e.printStackTrace(); 
      } 
  } 
} 


复制代码

4.总结

1.ProcessBuilder

2.Runtime

3.读缓冲区:因为shell脚本有时候有echo输出或打印,导致缓冲区被用完了,为了避免这种情况,需要用将缓冲区数据读出来。同时可以打印shell具体运行状态。

BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream())); 
      StringBuffer sb = new StringBuffer(); 
      String line; 
      while ((line = brreadLine()) != null) { 
        sb.append(line).append("/n"); 
      } 
      String result = sbtoString(); 
      System.out.println(result); 
复制代码

4.因为其中一个模型只能运行在本地annacoda虚拟环境中,而java调用的时候总是不能通过source activate 激活这个环境。 后面以为是环境变量路径没有配置的问题,尝试在envp中添加环境变量,失败; 查找网络之后,发现原来java在调用shell的时候,默认用的是系统/bin/下的指令。特别是你用root权限运行的时候。 这时候,你要在/bin下加软链了。针对我上面的例子,就要在/bin下加软链。--这个未尝试。后面封装服务解决。

原文  https://juejin.im/post/5d071b4251882513cc52fee2
正文到此结束
Loading...