java调用shell脚本及注意事项

需求:

get方法下载远程zip包,然后zip包解压,取出第一级目录再次进行压缩获取新的压缩zip包。

问题:

如果选择使用java代码的IO流操作,在不确定zip包大小的情况下可能会占用很大的内存,所以选择异步调用shell脚本来实现这个操作;

介绍:

1、通过ProcessBuilder进行调度

//解决脚本没有执行权限
ProcessBuilder builder = new ProcessBuilder("/bin/chmod", "755", scriptPath);
Process process = builder.start();
process.waitFor();


2、直接通过系统的Runtime类执行shell

        Runtime类封装了运行时的环境。每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。
一般不能实例化一个Runtime对象,应用程序也不能创建自己的 Runtime 类实例,但可以通过 getRuntime 方法获取当前Runtime运行时对象的引用。
      一旦得到了一个当前的Runtime对象的引用,就可以调用Runtime对象的方法去控制Java虚拟机的状态和行为。 

//SHELL_FILE_DIR + RUNNING_SHELL_FILE为脚本的全路径,后面传递给shell脚本多个参数用空格分隔
Sting cmd = SHELL_FILE_DIR + RUNNING_SHELL_FILE + " "+param1+" "+param2+" "+param3
//RunTime执行脚本
Process ps = Runtime.getRuntime().exec(cmd);
//waitFor等待shell运行完,返回值如果为0,则表明正常运行完
int execStatus = ps.waitFor();


遇到的问题:

1、没权限运行。通过ProcessBuilder来设置文件的权限

//解决脚本没有执行权限,scriptPath为脚本全路径
ProcessBuilder builder = new ProcessBuilder("/bin/chmod", "755", scriptPath);
Process process = builder.start();
process.waitFor();


2、调用shell脚本提示:No such file or directory

原因:文件格式不正确导致,在windows下编写的sh文件,文件是DOS格式。使用:set ff=unix 强制将文件转换为unix格式。

具体操作:

vim模式打开这个shell脚本,查看编码格式后设置成unix编码,输入:set ff?,查看格式是否是fileformat=unix;如果不是,设置成unix

:set ff=unix后保存(:wq)即可。

3、shell脚本输出太大,程序卡死问题

        Java在执行Runtime.getRuntime().exec(command)之后,Linux会创建一个进程,该进程与JVM进程建立三个管道连接,标准输入流、标准输出流、标准错误流。

        当标准输出流或标准错误流非常庞大的时候,会出现调用waitFor方法卡死的bug。真实的环境中,当标准输出在10000行左右的时候,就会出现卡死的情况。

原因分析:假设linux进程不断向标准输出流和标准错误流写数据,而JVM却不读取,数据会暂存在linux缓存区,当缓存区存满之后导致该进程无法继续写数据,会僵死,导致java进程会卡死在waitFor()处,永远无法结束。

解决方式:由于标准输出和错误输出都会向Linux缓存区写数据,而脚本如何输出这两种流是Java端不能确定的。为了不让shell脚本的子进程卡死,这两种输出需要分别读取,而且不能互相影响。所以必须新开两个线程来进行读取。

new Thread() {  public void run() {  BufferedReader br1 = new BufferedReader(new InputStreamReader(is1));  try {  String line1 = null;  while ((line1 = br1.readLine()) != null) {  if (line1 != null){}  }  } catch (IOException e) {  e.printStackTrace();  }  finally{  try {  is1.close();  } catch (IOException e) {  e.printStackTrace();  }  }  }  }.start();  new Thread() {   public void  run() {   BufferedReader br2 = new  BufferedReader(new  InputStreamReader(is2));   try {   String line2 = null ;   while ((line2 = br2.readLine()) !=  null ) {   if (line2 != null){}  }   } catch (IOException e) {   e.printStackTrace();  }   finally{  try {  is2.close();  } catch (IOException e) {  e.printStackTrace();  }  }  }   }.start();

下面提供工具类和自己的shell脚本:

工具类:

import org.apache.commons.lang.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.*;
import java.util.Arrays;public class ShellCommandUtils {/** 日志*/private final static Logger logger = LoggerFactory.getLogger(ShellCommandUtils.class);/*** @Description: 执行shell** @param scriptPath :脚本路径* @param param 脚本参数* @Return: void* @Date: 2019/3/22 */public static int execShell(String scriptPath, String... param) {logger.info("调用处理压缩包的shell脚本,params=" + param.toString());Arrays.stream(param).forEach(item-> logger.info(item));//执行结果int result = 1;try {String[] cmd = new String[]{scriptPath};//为了解决参数中包含空格cmd = (String[]) ArrayUtils.addAll(cmd, param);logger.info("调用处理压缩包的shell脚本,cmd=" + cmd.toString());Arrays.stream(cmd).forEach(item-> logger.info(item));logger.info("解决脚本没有执行权限逻辑start");//解决脚本没有执行权限ProcessBuilder builder = new ProcessBuilder("/bin/chmod", "755", scriptPath);Process process = builder.start();process.waitFor();logger.info("解决脚本没有执行权限逻辑end");logger.info("开始执行runtime的脚本start");Process ps = Runtime.getRuntime().exec(cmd);logger.info("把缓冲区读出来打log  start");//处理InputStream的线程,获取进程的标准输入流final InputStream is1 = ps.getInputStream();//获取进城的错误流final InputStream is2 = ps.getErrorStream();//启动两个线程,一个线程负责读标准输出流,另一个负责读标准错误流new Thread() {public void run() {BufferedReader br1 = new BufferedReader(new InputStreamReader(is1));try {String line1 = null;while ((line1 = br1.readLine()) != null) {if (line1 != null){}}} catch (IOException e) {e.printStackTrace();}finally{try {is1.close();} catch (IOException e) {e.printStackTrace();}}}}.start();new Thread() {public void  run() {BufferedReader br2 = new  BufferedReader(new  InputStreamReader(is2));try {String line2 = null ;while ((line2 = br2.readLine()) !=  null ) {if (line2 != null){}}} catch (IOException e) {e.printStackTrace();}finally{try {is2.close();} catch (IOException e) {e.printStackTrace();}}}}.start();//等待shell脚本结果int execStatus = ps.waitFor();logger.info("执行runtime的脚本end");logger.info("shell脚本执行结果--execStatus ="+execStatus);result = execStatus;logger.info("返回值为result=" + result);} catch (Exception e) {logger.error("调用处理压缩包的shell出现异常!", e);}return result;}}


shell脚本:

#!/bin/sh
#处理压缩包
fileName=$1
url=$2
homePath=$3#开始处理数据逻辑
echo fileName=$fileName, url=$url, homePath=$homePath#判断参数不为空
if [  -n "$fileName" ];  then if [  -n "$url" ]; then#0.cd到对应目录cd $homePath#1.调用get方法获取zip包并下载到本地wget -O $fileName.zip $url#2.解压zip包unzip $fileName.zip#3.删除zip包rm -f $fileName.zip#4.进入解压完的文件夹cd $fileName#5.压缩当前文件夹下所有文件为指定文件名的zipzip -r ../$fileName.zip ./*#6.删除之前解压的文件夹rm -rf $homePath$fileNamefi
fiecho "deal package end"

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/497490.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

潘建伟团队进行人类首次洲际量子通信,给奥地利发去了什么?

来源:澎湃新闻概要:世界首颗量子通信实验卫星完成目标;世界首条量子保密通信“京沪干线”开通;世界首次洲际量子通信……世界首颗量子通信实验卫星完成目标;世界首条量子保密通信“京沪干线”开通;世界首次…

java ps old gen perm gen,ElasticSearch 的一次非正常master脱离的调查

一共有4个节点的cluster,其中es4 是master,某个时间突然es1脱离了整个cluster,调查过程如下:[esbigdata1 logs]$ date; ssh bd4 date2012年09月03日 星期一09:41:26 CST2012年09月03日 星期一09:41:00 CSTes4比es1慢26秒&#xff…

《人工智能标准化白皮书(2018版)》发布|附下载

来源:光明网概要:1月18日下午,2018人工智能标准化论坛在京召开,本次论坛发布了《人工智能标准化白皮书(2018版)》。1月18日下午,2018人工智能标准化论坛在京召开,本次论坛发布了《人…

matlab7.0停止工作,matlab7.0闪退是怎么回事_matlab7.0闪退怎么办

描述兼容性引起的matlab7.0闪退1、在桌面的matlab图标上点击右键,选择“属性”2、选择“兼容性”3、勾选“以兼容模式运行这个程序”,再选择“Windows2000”4点击“确定”matlab7.0闪退的解决办法1)如果不是Intel的CPU,要添加环境变量--〉系统…

java调用shell脚本并传递参数

最近业务上需要java调用执行shell脚本进行一些业务处理,写了个demo,记录下。 主要代码 RequestMapping("/copy/database")ResponseBodypublic String copyDatabase(HttpServletRequest request,String dbCode,String targetPath){JSONObject …

贝叶斯机器学习前沿进展

来源:人机与认知实验室概要:随着大数据的快速发展,以概率统计为基础的机器学习在近年来受到工业界和学术界的极大关注,并在视觉、语音、自然语言、生物等领域获得很多重要的成功应用。摘要 随着大数据的快速发展,以概率…

matlab knn,MATLAB K近邻算法 — knnsearch() 函数 | 学步园

K近邻IDX knnsearch(X,Y) finds the nearest neighbor in X for each point inY. X is an MX-by-N matrix and Y is an MY-by-N matrix. Rows of X and Ycorrespond to observations and columns correspond to variables. IDX isa column vector with MY rows. Each row in I…

数据库事务的概念及其实现原理

目录 1. 认识事务 1.1 为什么需要数据库事务1.2 什么是数据库事务1.3 事务如何解决问题1.4 事务的ACID特性以及实现原理概述2.并发异常与并发控制技术 2.1 常见的并发异常2.2 事务的隔离级别2.3 事务隔离性的实现——常见的并发控制技术 2.3.1 基于封锁的并发控制2.3.2 基于时…

Fast.ai推出NLP最新迁移学习方法「微调语言模型」,可将误差减少超过20%!

原文来源:arxiv作者:Jeremy Howard、Sebastian Ruder「雷克世界」编译:嗯~是阿童木呀可以这样说,迁移学习已经促使计算机视觉领域发生了具有革命性的变化,但对于自然语言处理(NLP)中的现有方法来…

php去除txt重复,用vbscript实现从文本文件中删除所有重复行的代码

这篇文章主要为大家介绍了关于从文本文件中删除重复名字的类似问题,需要的朋友可以参考一下问:您好,脚本专家!如何从文本文件中删除所有重复行?-- SW答:您好,SW。您知道,成为一名脚本…

Spring Data JPA事务管理

1、事务基础概念_四大特性 数据库中事务的四大特性(ACID),如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: ⑴ 原子性(Atomicity) 原子性,是指事务包含的所有…

教育部发文:AI、算法等2018年进入全国高中课程!

来源:全球人工智能概要:1月16日上午,教育部召开新闻发布会,介绍了《普通高中课程方案和语文等学科课程标准(2017年版)》的有关情况,并重新修订了语文等14门学科的课程标准。1月16日上午&#xf…

经典php代码,HTML_php教程:经典PHP代码,经典循环例子 HTMLHEAD - phpStudy

经典循环例子经典循环例子for($counter 1; $counter < 6; $counter) //循环6次{print("counter is $counter\n"); //打印6次}?>for的高级运用for的高级运用/*** 打印必要的说明文字*/print("距离星期一还有几天&#xff1f;\n");print(&…

JPA事务示例分析

在这个工程中&#xff0c;定义一个名为User的实体&#xff1a; Entity Data NoArgsConstructor public class User {IdGeneratedValueprivate Long id;Size(max 5)private String name;Max(50)private Integer age;public User(String name, Integer age) {this.name name;t…

智能零售来了!Amazon Go无人商店周一正式对公众开放

来源&#xff1a;网络大数据概要&#xff1a;经过近 14 个月只对亚马逊公司员工开放的试运行&#xff0c;周一这家标着 Amazon Go 标志的店面将公开亮相&#xff0c;这是亚马逊近年来投入最多努力的项目之一&#xff0c;旨在重塑实体购物的体验。据《西雅图时报》报道&#xff…

python函数时间,python之时间函数

用time模块的strftime函数时间日期的格式化时间import timeprint(time.strftime(%y/%m/%d %H:%M:%S %A))格式化符号说明格式化符号说明格式化符号说明%Y年(2019)%B月(June)%A星期(Thursday)%y年(19)%b月(Jun)%a星期(Thu)%I时(02)%m月(06)%w星期(4)(0~6)(0是周日)%H时(14)%M分(2…

JPA - EntityTransaction与事务

EntityTransaction 接口用来管理资源层实体管理器的事务操作&#xff0c;通过调用实体管理器的getTransaction方法 获得其实例。 其常用方法如下&#xff1a; ① begin 用于启动一个事务&#xff0c;此后的多个数据库操作将作为整体被提交或撤消。 若这时事务已启动则会抛出…

看懂GE Predix ,就看懂了工业互联网

来源&#xff1a;小黑羊JoinWings概要&#xff1a;Predix是GE推出的针对整个工业领域的基础性系统平台&#xff0c;这是一个开放的平台&#xff0c;它可以应用在工业制造、能源、医疗等各个领域。Predix是GE推出的针对整个工业领域的基础性系统平台&#xff0c;这是一个开放的平…

php传递数据给jquery,将值从php传递给jquery

我需要一些帮助&#xff0c;我想知道如何将一个值从PHP变量传递给jquery脚本&#xff1f;我正在做的是打开一个模式窗口&#xff0c;从mysql浏览器创建的元素列表中&#xff0c;所以我需要传递一个变量值的锚点。这是我的代码&#xff1a;$query_tours "Select * from to…

JPA和事务管理

1 事务 1.1事务管理方式 spring支持编程式事务管理和声明式事务管理两种方式。 编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理&#xff0c;spring推荐使用TransactionTemplate。 声明式事务管理建立在AOP之上的…