java调用shell脚本及注意事项

您所在的位置:网站首页 写脚本的注意事项 java调用shell脚本及注意事项

java调用shell脚本及注意事项

2024-07-15 15:13:29| 来源: 网络整理| 查看: 265

需求:

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.压缩当前文件夹下所有文件为指定文件名的zip zip -r ../$fileName.zip ./* #6.删除之前解压的文件夹 rm -rf $homePath$fileName fi fi echo "deal package end"

 



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭