Java调用Shell命令和脚本[通俗易懂]

Java调用Shell命令和脚本[通俗易懂]1.介绍有时候我们在Linux中运行Java程序时,需要调用一些Shell命令和脚本。而Runtime.getRuntime().exec()方法给我们提供了这个功能,而且

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

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,表示调用命令将在当前程序执行的目录中执行,因此调用到其他目录中的文件和脚本最好使用绝对路径。各个参数的含义:

  1. cmdarray: 包含所调用命令及其参数的数组。 
  2. command: 一条指定的系统命令。
  3. envp: 字符串数组,其中每个元素的环境变量的设置格式为name=value;如果子进程应该继承当前进程的环境,则该参数为 null。
  4. 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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/170873.html原文链接:https://javaforall.net

(0)
上一篇 2022年8月18日 下午4:00
下一篇 2022年8月18日 下午4:16


相关推荐

  • ios-anchorPoint、position理解[通俗易懂]

    ios-anchorPoint、position理解[通俗易懂]anchorPoint(锚点)是layer的一个属性,下面我们来看看其对view的影响,本文主要通过图片方式展现:锚点用单位坐标来描述也就是图层的相对坐标。在苹果文档中说明左下是(0,0),右上是(1,1),经过试验这个是错的,实际上:图层左上角是{0,0},右下角是{1,1},取值范围不限。单位坐标的意思是指以视图长款为单位来计算,坐标系展示如下:默认一个视图的锚

    2022年10月8日
    4
  • PyCharm快捷键大全(windows+mac)

    PyCharm快捷键大全(windows+mac)Pycharm 有着丰富且强大的快捷键组合 如果能熟练掌握常见快捷键的使用 那么绝对能提高你代码的编写效率和质量 之前写过一篇 Pycharm 常用的 10 个 windows 快捷键 Pycharm 最

    2026年3月27日
    3
  • css3实现遮罩层_div遮罩层

    css3实现遮罩层_div遮罩层JS+CSS简单实现DIV遮罩层显示隐藏

    2022年4月21日
    65
  • postgresql 数据库 alter table alter column set default 的一些实践

    postgresql 数据库 alter table alter column set default 的一些实践os centos7 4db postgresql10 11 创建表后 有时需要对表进行 setdefault 或者 dropdefault 设置 版本 cat etc centos releaseCentO 4 1708 Core su postgres psql c selectversio

    2026年3月16日
    2
  • activiti7实战教程(二)作图「建议收藏」

    activiti7实战教程(二)作图「建议收藏」IDEA:2018.2.2插件:actibpm新建BPMN文件依次拖出需要的组件,最好按照流程的顺序进行拖出,这样后面看xml的时候比较直观。修改每个节点的名称填写每个审批节点的伪码:科室长、分管领导、采购人员、以及网关的伪码表达式这样流程图就做好了。接下来要根据流程图生成XML文件和png图片复制一份流程图,修改名称:后缀名加上20.xml在xml文件上右键到此为止,整个流程图作图就完整的结束了。另外呢告知一点,流程图…

    2022年7月21日
    36
  • 最全面 在 Pycharm 中配置并使用 pipenv 虚拟环境

    最全面 在 Pycharm 中配置并使用 pipenv 虚拟环境1 为 Python 项目创建虚拟环境 1 1 安装 pipenvpipins 2 创建虚拟环境跳转到项目文件夹打开 cmd 窗口并输入以下代码 pipenvinstal 3 为虚拟环境安装指定包 pipenvinstal 如果使用默认安装源 大多数情况下会卡在 locking 阶段 解决办法有二更改安装源 修改项目文件夹下的 Pipfile 文

    2026年3月27日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号