Java调用Shell命令和脚本的实现

 更新时间:2021年02月23日 10:20:42   作者:GatsbyNewton  
这篇文章主要介绍了Java调用Shell命令和脚本的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

1.介绍

有时候我们在Linux中运行Java程序时,需要调用一些Shell命令和脚本。而Runtime.getRuntime().exec()方法给我们提供了这个功能,而且Runtime.getRuntime()给我们提供了以下几种exec()方法:

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) 
在有指定环境和工作目录的独立进程中执行指定的字符串命令。 

其中,其实cmdarray和command差不多,同时如果参数中如果没有envp参数或设为null,表示调用命令将在当前程序执行的环境中执行;如果没有dir参数或设为null,表示调用命令将在当前程序执行的目录中执行,因此调用到其他目录中的文件和脚本最好使用绝对路径。各个参数的含义:

  • cmdarray: 包含所调用命令及其参数的数组。
  • command: 一条指定的系统命令。
  • envp: 字符串数组,其中每个元素的环境变量的设置格式为name=value;如果子进程应该继承当前进程的环境,则该参数为 null。
  • dir: 子进程的工作目录;如果子进程应该继承当前进程的工作目录,则该参数为 null。

细心的读者会发现,为了执行调用操作,JVM会启一个Process,所以我们可以通过调用Process类的以下方法,得知调用操作是否正确执行:

abstract int waitFor() 
导致当前线程等待,如有必要,一直要等到由该 Process 对象表示的进程已经终止。 

进程的出口值。根据惯例,0 表示正常终止;否则,就表示异常失败。
另外,调用某些Shell命令或脚本时,会有返回值,那么我们如果捕获这些返回值或输出呢?为了解决这个问题,Process类提供了:

abstract InputStream getInputStream() 
获取子进程的输入流。 最好对输入流进行缓冲。

2.调用Shell命令

这里为了说明问题,我仅用tar命令进行演示。tar命令是一个打包而不进行压缩的命令。同时,为了检查tar的调用是否被正常执行,我将调用waitFor()方法。

private void callCMD(String tarName, String fileName, String... workspace){
 try {
 String cmd = "tar -cf" + tarName + " " + fileName;
//      String[] cmd = {"tar", "-cf", tarName, fileName};
 File dir = null;
 if(workspace[0] != null){
  dir = new File(workspace[0]);
  System.out.println(workspace[0]);
 }
 process = Runtime.getRuntime().exec(cmd, null, dir);
//     process = Runtime.getRuntime().exec(cmd);
 int status = process.waitFor();
 if(status != 0){
  System.err.println("Failed to call shell's command and the return status's is: " + status);
 }
 }
 catch (Exception e){
 e.printStackTrace();
 }
}

注意:如果把命令放到一个String[]中时,必须把命令中每个部分作为一个元素存在String[]中,或者是把命令按照空格符分割得到的String[]。

String[] cmd = {"tar", "-cf", tarName, fileName}; //right
String[] cmd = {"tar -cf", tarName, fileName};  //error

为了说明dir参数的作用,我特地把该Java程序和要打包的目录hive/放在不同的目录:

/root/workspace/eclipse/Test/src/edu/wzm/CallShell.java
/root/experiment/hive

如果我不设置dir或设dir为null,那么fileName不得不是相对路径,最好是绝对路径:

call.callCMD("/root/experiment/hive.tar", "/root/experiment/hive", null);
// OR
call.callCMD("/root/experiment/hive.tar", "/root/experiment/hive");

如果我设置了dir指向了hive所在的父目录就好办多了:

call.callCMD("hive.tar", "hive", "/root/experiment/");

3.调用Shell脚本

Java调用Shell命令和调用Shell脚本的操作一模一样。我这里介绍另外几个方面:

  1. 给脚本传递参数;
  2. 捕获调用的输出结果;
  3. envp的使用。

给脚本传递参数,这个操作很简单,无非是把参数加到调用命令后面组成String,或String[]。

捕获调用输出信息,前面也提到过用Process.getInputStream()。不过,建议最好对输入流进行缓冲:

BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));

另外,envp是一个String[],并且String[]中的每一个元素的形式是:name=value。如:我的Linux系统中没有以下环境变量,但是我把它们写在Java代码中,作为envp:

val=2
call=Bash Shell

我要调用的Shell脚本是:/root/experiment/test.sh。

#!/usr/bin/env bash
 
args=1
if [ $# -eq 1 ];then
 args=$1
 echo "The argument is: $args"
fi
 
echo "This is a $call"
start=`date +%s`
sleep 3s
end=`date +%s`
cost=$((($end - $start) * $args * $val))
echo "Cost Time: $cost"

Java调用代码是:

private void callScript(String script, String args, String... workspace){
 try {
 String cmd = "sh " + script + " " + args;
//     String[] cmd = {"sh", script, "4"};
 File dir = null;
 if(workspace[0] != null){
  dir = new File(workspace[0]);
  System.out.println(workspace[0]);
 }
 String[] evnp = {"val=2", "call=Bash Shell"};
 process = Runtime.getRuntime().exec(cmd, evnp, dir);
//      process = Runtime.getRuntime().exec(cmd);
 BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));
 String line = "";
 while ((line = input.readLine()) != null) {
  System.out.println(line);
 }
 input.close();
 }
 catch (Exception e){
 e.printStackTrace();
 }
}
 
public static void main(String[] args) {
 // TODO Auto-generated method stub
 CallShell call = new CallShell();
 call.callScript("test.sh", "4", "/root/experiment/");
}

输出:
/root/experiment/
The argument is: 4
This is a Bash Shell
Cost Time: 24

到此这篇关于Java调用Shell命令和脚本的实现的文章就介绍到这了,更多相关Java调用Shell命令和脚本内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 本地启动RocketMQ未映射主机名产生的超时问题最新解决方案

    本地启动RocketMQ未映射主机名产生的超时问题最新解决方案

    这篇文章主要介绍了本地启动RocketMQ未映射主机名产生的超时问题,本文给大家分享最新解决方案,感兴趣的朋友跟随小编一起看看吧
    2024-02-02
  • SpringCloud Feign超详细讲解

    SpringCloud Feign超详细讲解

    Feign是Netflix公司开发的一个声明式的REST调用客户端; Ribbon负载均衡、 Hystrⅸ服务熔断是我们Spring Cloud中进行微服务开发非常基础的组件,在使用的过程中我们也发现它们一般都是同时出现的,而且配置也都非常相似
    2022-10-10
  • mybatis空值插入处理的解决方法

    mybatis空值插入处理的解决方法

    本文主要介绍了mybatis空值插入处理的解决方法,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • Mybatis-Plus分页的使用与注意事项

    Mybatis-Plus分页的使用与注意事项

    分页查询每个人程序猿几乎都使用过,下面这篇文章主要给大家介绍了关于Mybatis-Plus分页的使用与注意事项的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-04-04
  • Java 深入浅出讲解代理模式

    Java 深入浅出讲解代理模式

    代理模式是Java常见的设计模式之一。所谓代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象
    2022-03-03
  • Java日常练习题,每天进步一点点(12)

    Java日常练习题,每天进步一点点(12)

    下面小编就为大家带来一篇Java基础的几道练习题(分享)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧,希望可以帮到你
    2021-07-07
  • Spring中@Cacheable注解的使用详解

    Spring中@Cacheable注解的使用详解

    这篇文章主要介绍了Spring中@Cacheable注解的使用详解,Spring框架提供了@Cacheable注解来轻松地将方法结果缓存起来,以便在后续调用中快速访问,本文将详细介绍@Cacheable注解的使用方法,并从源码级别解析其实现原理,需要的朋友可以参考下
    2023-11-11
  • Spring Boot MQTT Too many publishes in progress错误的解决方案

    Spring Boot MQTT Too many publishes in progress错误的解决方

    本文介绍Spring Boot MQTT Too many publishes in progress错误的解决方案,文章围绕主题展开详细的内容介绍,具有一定的参考价值,感兴趣的小伙伴可以参考一下
    2022-07-07
  • spring cloud中启动Eureka Server的方法

    spring cloud中启动Eureka Server的方法

    本篇文章主要介绍了spring cloud中启动Eureka Server的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-01-01
  • Springboot登录验证的统一拦截处理的实现

    Springboot登录验证的统一拦截处理的实现

    如果不进行统一的拦截处理,每次用户请求你都要去进行用户的信息验证,所以本文主要介绍了Springboot登录验证的统一拦截处理的实现,感兴趣的可以了解一下,感兴趣的可以了解一下
    2023-09-09

最新评论