java 执行linux 命令

文章目录

  • 前言
  • 一、linux命令执行
  • 二、使用步骤
  • 三、踩坑

前言

java 执行linux 命令;
本文模拟复制linux文件到指定文件夹后打zip包后返回zip名称,提供给下载接口下载zip;

一、linux命令执行

linux命令执行Process process = Runtime.getRuntime().execProcess process = new ProcessBuilder(commands).start();

   
    /**
     * 执行Linux命令
     */
    public static void execCommand(String commands) throws IOException {
        Process process = null;
        BufferedReader reader = null;
        try {
            //创建进程实例执行Linux命令
            process = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", commands});
            // 获取标准输入流
            reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                //log.info("linux----" + line);
            }
            // 等待进程结束
            int exitCode = process.waitFor();
            if (exitCode != 0) {
                log.error("执行Linux命令异常,exitCode={},linux command={}", exitCode, commands);
                throw new BusinessCheckException("执行Linux命令异常");
            }
        } catch (IOException | InterruptedException e) {
            log.error("执行Linux命令异常", e);
            throw new BusinessCheckException("执行Linux命令异常");
        } finally {
            if (reader != null) {
                reader.close();
            }
            if (process != null) {
                process.destroy();
            }
        }
    }

二、使用步骤

  1. 通过linux命令,打包目标数据到zip
public String downToZip(CorpQrCodeReq req, HttpServletResponse response) {
   		StopWatch sw = new StopWatch();
		// 参数校验
        if (CollectionUtils.isEmpty(req.getCorpIds()) || CollectionUtils.isEmpty(req.getCorpNames())) {
            return "0";
        }
        // 生成保存目录文件夹
        String uuid = UUID.randomUUID().toString().replace("-", "");
        String baseUploadPath = "/tmp/zip/"+uuid+"/";
        FileUtil.mkdir(baseUploadPath);
        try {
            //生成二维码到临时目录
            List<String> enterpriseIds = req.getCorpIds();
            List<String> enterpriseNames = req.getCorpNames();
            List<String> command = new ArrayList<>(enterpriseIds.size());
            // 拼接被复制的文件地址
            for (int i = 0; i < enterpriseIds.size(); i++) {
                String path = this.qrCode(CorpQrCodeReq.builder()
                        .corpIds(Lists.newArrayList(enterpriseIds.get(i)))
                        .corpNames(Lists.newArrayList(enterpriseNames.get(i))).build());
                command.add(path + " ");
            }
            sw.stop();
            log.info(sw.getLastTaskName() + sw.getTotalTimeSeconds() + "s");
            sw.start("执行cp命令");
            String property = System.getProperty("line.separator");
            //拼接shell脚本
            String sb = " for i in  " + String.join(" ", command) +
                    property +
                    "do" +
                    property +
                    " cp -n  \"$i\" " + baseUploadPath +
                    property +
                    "done";
            //执行cp命令
            execCommand(sb);
            sw.stop();
            log.info(sw.getLastTaskName() + sw.getTotalTimeSeconds() + "s");
            sw.start("执行压缩命令");
            //执行压缩命令 统一压缩比一个一个压缩进去效率高 
            //-j忽略源文件路径,直接打包目标文件
            String zipCommand = " /bin/zip -1 -j " + baseUploadPath.concat(".zip") + " " + baseUploadPath + "/*";
            execCommand(zipCommand);
            sw.stop();
            log.info(sw.getLastTaskName() + sw.getTotalTimeSeconds() + "s");
            log.info(sw.prettyPrint());
            return uuid;
        } catch (Exception e) {
            log.error("压缩包下载失败 ", e);
            throw new BusinessCheckException("压缩包下载失败");
        }
    }
  1. 根据uuid,下载zip文件(2个接口,一个是根据条件生成zip,另一个根据zip名称下载),此处下载应用了nginx的X-Accel-Redirect,具体使用方法参考springboot X-Accel-Redirect 大文件下载实现
    public void downZip(String path, HttpServletResponse response) {
        try {
            String baseUploadPath ="/tmp/zip/";
            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("企业二维码", StandardCharsets.UTF_8.toString()) + ".zip");
            //设置URI给nginx进行内部的跳转
            response.setHeader("X-Accel-Redirect", "/upload" + baseUploadPath.concat(path).concat(".zip"));
        } catch (Exception e) {
            log.error(" 二维码压缩包下载失败 ", e);
            throw new BusinessCheckException("二维码压缩包下载失败");
        }
    }

三、踩坑

  1. linux 和 java 2个进程异步问题

linux命令执行后,和java服务是2个进程。
当linux命令执行过程期间,java下面的业务服务已触发时(比如文件数量较大,而下载接口触发较快时)会造成数据不完整(zip包打包不全,一般一个文件没有)。
此时我们需要利用 读取执行流 + process.waitFor(),等待linux进程结束后再做业务处理。

  1. 关于Process初始化
 Process process = null;
 // 如果commands拼接的命令中包含空格 会自动识别为2段命令
 process = new ProcessBuilder(commands).start();
 // 不支持空格和|
 process = Runtime.getRuntime().exec(commands);
 // -c 表示cmd是一条命令,不会被截断
 process = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", commands});
  1. linux for cp 空格识别问题
    执行脚本如下:
for i in  "/data/mnt/www/corp-qr/769847/九台区九台中由 生活服务部.jpg"
do
 cp -n  $i  /data/zip/5e0e67f59c524a4e9851abd3a3dfe0ac
done

此时执行命令报错:cp: 无法获取"/data/mnt/www/corp-qr/769847/九台区九台中由" 的文件状态(stat): 没有那个文件或目录 cp: 无法获取"生活服务部.jpg" 的文件状态(stat): 没有那个文件或目录,linux 会将目标文件解析成2个文件。

解决方案:

"/data/mnt/www/corp-qr/769847/九台区九台中由 生活服务部.jpg" 修改为 "/data/mnt/www/corp-qr/769847/*"cp -n  $i  /data/zip/5e0e67f59c524a4e9851abd3a3dfe0ac 修改为 cp -n  "$i"  /data/zip/5e0e67f59c524a4e9851abd3a3dfe0ac
  1. 执行效率优化
    一千个文件测试结果:
    a. 文件循环时直接打包到zip"/bin/zip -rj " + baseUploadPath.concat(".zip") + " " + baseUploadPath + "/*";效率不如cp 到文件夹下压缩文件夹
    b. 调整压缩率 zip -1
    c. 文件循环时直接cp,由于execCommand执行linux命令要等返回结果再执行,所以效率也不高

  2. cp 文件覆盖问题
    同名文件cp linux会提示是否覆盖,如果通过java执行cp,无法给予是否覆盖的回应,报错:没有那个文件或目录,如果忽略覆盖提示?
    覆盖提示原因:
    在这里插入图片描述
    我们执行cp时 实际linux执行的是cp -i -i 表示覆盖前提示

-- 命令前加反斜线忽略alias
\cp /var/tmp/test.txt /tmp 
-- 使用命令全路径
/bin/cp /var/tmp/test.txt /tmp
-- 先取消别名再复制(不推荐)
unalias cp
-- 不覆盖
cp -n /var/tmp/test.txt /tmp

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【已解决】java 无法将类 XX类中的构造器 X应用到给定类型

原因&#xff1a; 实际参数列表和形式参数列表长度不同 解决方法&#xff1a; 给类添加AllArgsConstructor注解即可。

什么是跨站脚本攻击(XSS)?如何防止它?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

猫粮哪个牌子质量好性价比高?口碑比较好的主食冻干猫粮牌子推荐

猫咪生骨肉主食冻干猫粮喂养方式是越来越火了&#xff0c;作为一个离职的十年经验宠物护理师&#xff0c;对宠物健康营养方面的知识一直在研究&#xff0c;不光是为了我自己养的猫咪身体健康&#xff0c;也要为客户的猫咪健康负责&#xff01;现在很多养猫人士对主食冻干猫粮喂…

RocketMQ 服务搭建

目录 概述RocketMQ 单机服务搭建搭建架构相关地址前置操作NameServer 启动配置启动解决 java 版本的问题 Broker 启动测试关闭 结束 概述 学习此文&#xff0c;可以快速的搭建一个单机的 RocketMQ 服务。 RocketMQ 单机服务搭建 搭建架构 相关地址 RocketMQ官网地址二进制下…

什么台灯好用不伤眼睛?适合考公使用的台灯推荐

随着时代的发展与进步&#xff0c;不管是办公族还是学生党的压力也越来越大的&#xff0c;不少人在晚上回去之后仍然需要学习、工作&#xff0c;这样的一件试几乎成为了“家常便饭”&#xff0c;而这个过程中必不可少就是台灯。有些人为了保护眼睛会选择护眼台灯&#xff0c;但…

关于AISD300系列三相智能安全配电装置的详细介绍-安科瑞 蒋静

1概述 AISD300系列三相智能安全配电装置是安科瑞专为低压配电侧开发的一款智能安全配电产品&#xff0c;本产品主要针对低压配电系统人身触电、线路老化、短路、漏电等原因引起电气安全问题而设计。 产品主要应用于学校、加油站、医院、银行、疗养院、康复中心、敬老院、酒店…

大洋钻探系列之四“决心号”钻探船

乔迪斯决心号&#xff08;英文&#xff1a;JOIDES Resolution&#xff09;大洋钻探船是大洋钻探所使用的一艘钻探船&#xff0c;是美国Sedco公司和英国石油公司所属的一艘商用石油勘探船“Sedco/BP 471号”改装而来的。“乔迪斯”音译自地球深部取样海洋研究机构联合体&#xf…

Zebec 推出由 Visa、万事达网络支持的即时支付卡

“Zebec 现已推出全新的加密支付卡&#xff0c;该卡由 Visa、万事达网络支持&#xff0c;具备即时、多链、非托管、无需 KYC、免费等特性&#xff0c;其能够通过加密钱包与多条主流公链链接并直接调用支付&#xff0c;这将是加密支付领域的里程碑事件。” 在 2023 年的 12 月 8…

易安联威胁检测平台极简SaaS化部署,分钟实现安全接入

EnDTA 天织DNS威胁分析平台 它来了&#xff0c;它来了 永久免费版与企业版 正式开放 2023年6月&#xff0c;易安联全新威胁检测产品EnDTA天织DNS威胁分析平台面向全网正式开放公测&#xff0c;获得了超过50的测评反馈。经过数月的优化&#xff0c;EnDTA焕新升级归来&#xff…

计算机网络:数据链路层(网桥)

带你速通计算机网络期末 目录 一、冲突域和广播域 二、网桥介绍 三、网桥分类—―透明网桥 四、网桥分类―—源路由网桥 五、多接口网桥―—以太网交换机 总结 一、冲突域和广播域 冲突域:在同一个冲突域中的每一个节点都能收到所有被发送的帧。简单的说就是同一时间内只…

Python 模块的使用

本篇主要为python 模板介绍和使用&#xff0c;包含如何创建和使用自定义模块&#xff0c;引入模块的方式及包内容介绍。 概述 在项目开发中随着代码量越来越多&#xff0c;代码就会越来越难以维护。为了解决难以维护的问题&#xff0c;我们把很多相似功能的函数分组&#xff0…

bugku--Simple_SSTI_1---2

第一题 看到一句话&#xff0c;需要传入一个传参为flag 设置一个变量为 secret_key 构造paykoad /?flagsecret_key 但是发现什么都没有 SSTI模版注入嘛 这里使用的是flask模版 Flask提供了一个名为config的全局对象&#xff0c;可以用来设置和获取全局变量。 继续构造pa…

Angular+Nginx区域HIS医院信息管理系统源码

医院管理信息系统&#xff08;HIS&#xff09;是医院基本、重要的管理系统&#xff0c;是医院大数据的基础。“云”指系统采用云计算的技术和建设模式&#xff0c;具有可扩展、易共享、区域化、易协同、低成本、易维护、体验好的优势。“H”是医疗卫生&#xff0c;由原来医院 (…

1846_安全SPI

Grey 全部学习内容汇总&#xff1a;GitHub - GreyZhang/g_embedded: some embedded basic knowledge. 1846_安全SPI SPI是一种常见的通信方式&#xff0c;在汽车电子中比较常用。但是如果涉及到安全相关的设计&#xff0c;可能得考虑更多。而SPI协议本身没有很好的标准化&am…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《考虑场间功率时移的海上风电场群联合储能优化调度方法》

这个标题涉及到海上风电场群&#xff08;Offshore Wind Farm Cluster&#xff09;的联合储能优化调度方法&#xff0c;并强调了对场间功率时移的考虑。以下是对标题各部分的解读&#xff1a; 海上风电场群&#xff1a; 指的是多个相邻或连接的海上风电场的集合体。通常&#xf…

销售技巧培训之如何提升网络销售技巧

销售技巧培训之如何提升网络销售技巧 随着互联网的普及&#xff0c;网络销售已经成为了一种重要的销售方式。对于许多企业来说&#xff0c;网络销售已经成为了一种重要的销售渠道。但是&#xff0c;要想在网络销售中取得成功&#xff0c;就需要掌握一些网络销售技巧。本文将介…

微信小程序ios中非cover组件点击重复触发地图tap事件

现象&#xff1a; map中使用view组件的click事件会重复触发地图的tap组件&#xff0c;只在ios上出现 <map id"maps" style"width: 100vw;height: 100vh;" :latitude"latitude" :longitude"longitude":markers"markers"…

关于put_response和get_response的总结

Response总结&#xff0c;共三种情况 &#xff08;1&#xff09;每一笔都等response -> 直接get_response 注意put_response的前提是当前的seq的body没有直接结束&#xff0c;这个body一定是最底层发req的那个seq的body &#xff08;2&#xff09;连续发送数据&#xff0…

Java8新特性:Lambda表达式

我是南城余&#xff01;阿里云开发者平台专家博士证书获得者&#xff01; 欢迎关注我的博客&#xff01;一同成长&#xff01; 一名从事运维开发的worker&#xff0c;记录分享学习。 专注于AI&#xff0c;运维开发&#xff0c;windows Linux 系统领域的分享&#xff01; 本…

Python: isinstance()判断当前对象类型

介绍 isinstance()是Python中的一个内置函数&#xff0c;用于检查一个对象是否是特定类的实例&#xff0c;或者是否继承自某个类。 isinstance()函数的语法如下&#xff1a; isinstance(object, classinfo) 其中&#xff1a; object&#xff1a;要检查的对象。classinfo&am…