在调用SHELL命令或DOS命令时,使用Runtime.getRuntime().exec(command);这个方法。但是执行某些命令时,程序可能就卡在那了,需要在执行的过程中新开启几个线程来不断地读取标准输出,以及错误输出,这样很不方便,好在commons-exec提供了更加友好的使用方式。

一、同步调用

commons-exec的command不需要考虑执行环境,比如windows下不需要添加"cmd /c "的前缀。
可以使用自定义的流来接受结果,比如使用文件流将结果保存到文件,使用网络流保存到远程服务器上等。
下面的例子模仿一个命令调用,这里只是一个ping localhost操作,这里为了方便,结果写在了内存中。

@Test
    public void testCommonExec() throws IOException {
        String command = "ping localhost";
        //接收正常结果流
        ByteArrayOutputStream susStream = new ByteArrayOutputStream();
        //接收异常结果流
        ByteArrayOutputStream errStream = new ByteArrayOutputStream();
        CommandLine commandLine = CommandLine.parse(command);
        DefaultExecutor exec = new DefaultExecutor();
        PumpStreamHandler streamHandler = new PumpStreamHandler(susStream, errStream);
        exec.setStreamHandler(streamHandler);
        int code = exec.execute(commandLine);
        System.out.println("退出代码: " + code);
        System.out.println(susStream.toString("GBK"));
        System.out.println(errStream.toString("GBK"));

如果使用JDK中的Runtime操作就复杂了:

 @Test
    public void testJdk() throws InterruptedException, IOException {
        final Process process = Runtime.getRuntime().exec("cmd /c ping localhost");
        new Thread(() -> {
            try (BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream(), "gbk"))) {
                String line;
                while ((line = br.readLine()) != null) {
                    try {
                        process.exitValue();
                        break; // exitValue没有异常表示进程执行完成,退出循环
                    } catch (IllegalThreadStateException e) {
                        // 异常代表进程没有执行完
                    System.out.println(line);
            } catch (IOException e) {
                throw new RuntimeException(e);
        }).start();
        process.waitFor();

二、异步调用

commons-exec支持异步调用

    @Test
    public void testCommonExec() throws InterruptedException, IOException {
        String command = "ping localhost";
        //接收正常结果流
        ByteArrayOutputStream susStream = new ByteArrayOutputStream();
        //接收异常结果流
        ByteArrayOutputStream errStream = new ByteArrayOutputStream();
        CommandLine commandLine = CommandLine.parse(command);
        DefaultExecutor exec = new DefaultExecutor();
        PumpStreamHandler streamHandler = new PumpStreamHandler(susStream, errStream);
        exec.setStreamHandler(streamHandler);
        ExecuteResultHandler erh = new ExecuteResultHandler() {
            @Override
            public void onProcessComplete(int exitValue) {
                try {
                    String suc = susStream.toString("GBK");
                    System.out.println(suc);
                    System.out.println("3. 异步执行完成");
                } catch (UnsupportedEncodingException uee) {
                    uee.printStackTrace();
            @Override
            public void onProcessFailed(ExecuteException e) {
                try {
                    String err = errStream.toString("GBK");
                    System.out.println(err);
                    System.out.println("3. 异步执行出错");
                } catch (UnsupportedEncodingException uee) {
                    uee.printStackTrace();
        System.out.println("1. 开始执行");
        exec.execute(commandLine, erh);
        System.out.println("2. 做其他操作");
        // 避免主线程退出导致程序退出
        Thread.currentThread().join();

如果使用JDK中的Runtime就复杂了:

@Test
    public void testJdk() throws IOException, InterruptedException {
        System.out.println("1. 开始执行");
        String cmd = "cmd /c ping localhost"; // 假设是一个耗时的操作
        execAsync(cmd, processResult -> {
            System.out.println("3. 异步执行完成,success=" + processResult.success + "; msg=" + processResult.result);
            System.exit(0);
        });
        // 做其他操作 ... ...
        System.out.println("2. 做其他操作");
        // 避免主线程退出导致程序退出
        Thread.currentThread().join();
    private void execAsync(String command, Consumer<ProcessResult> callback) throws IOException {
        final Process process = Runtime.getRuntime().exec(command);
        new Thread(() -> {
            StringBuilder successMsg = new StringBuilder();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream(), "GBK"))) {
                // 存放临时结果
                String line;
                while ((line = br.readLine()) != null) {
                    try {
                        successMsg.append(line).append("\r\n");
                        int exitCode = process.exitValue();
                        ProcessResult pr = new ProcessResult();
                        if (exitCode == 0) {
                            pr.success = true;
                            pr.result = successMsg.toString();
                        } else {
                            pr.success = false;
                            pr.result = IOUtils.toString(process.getErrorStream(), "utf-8");
                        callback.accept(pr); // 回调主线程注册的函数
                        break; // exitValue没有异常表示进程执行完成,退出循环
                    } catch (IllegalThreadStateException e) {
                        // 异常代表进程没有执行完
                    try {
                        // 等待100毫秒在检查是否完成
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
            } catch (IOException e) {
                throw new RuntimeException(e);
        }).start();
    private static class ProcessResult {
        boolean success;
        String result;

三、处理超时

commons-exec主要通过ExecuteWatchdog类来处理超时

@Test
    public void testCommonExecWatch() throws IOException {
        String command = "ping localhost";
        ByteArrayOutputStream susStream = new ByteArrayOutputStream();
        ByteArrayOutputStream errStream = new ByteArrayOutputStream();
        CommandLine commandLine = CommandLine.parse(command);
        DefaultExecutor exec = new DefaultExecutor();
        //设置一分钟超时
        ExecuteWatchdog watchdog = new ExecuteWatchdog(60 * 1000);
        exec.setWatchdog(watchdog);
        PumpStreamHandler streamHandler = new PumpStreamHandler(susStream, errStream);
        exec.setStreamHandler(streamHandler);
        try {
            int code = exec.execute(commandLine);
            System.out.println("result code: " + code);
            // 不同操作系统注意编码,否则结果乱码
            String suc = susStream.toString("GBK");
            String err = errStream.toString("GBK");
            System.out.println(suc + err);
        } catch (ExecuteException e) {
            if (watchdog.killedProcess()) {
                // 被watchdog故意杀死
                System.err.println("超时了");

Apache commons-exec提供一些常用的方法用来执行外部进程,Apache commons exec库提供了Watchdog来设监视进程的执行超时,同时也还实现了同步和异步功能,比JDK原生的Runtime要好用很多。

文章目录前言一、同步调用二、异步调用三、处理超时总结前言在调用SHELL命令或DOS命令时,使用Runtime.getRuntime().exec(command);这个方法。但是执行某些命令时,程序可能就卡在那了,需要在执行的过程中新开启几个线程来不断地读取标准输出,以及错误输出,这样很不方便,好在commons-exec提供了更加友好的使用方式。一、同步调用commons-exec的command不需要考虑执行环境,比如windows下不需要添加"cmd /c "的前缀。可以使用自定义的流
网上竟然搜不到详细一点的帖子,估计大家用JAVA去管理进程的场景比较少吧,只好自己总结一个。Java管理进程,API级别是使用Runtime.getRuntime().exec(“shell”); 使用Apache Commons Exec,让代码更加健壮。
Apache Commons Exec 提供了一个功能强大且灵活的 API,用于管理和控制外部进程。通过简化的 API、超时控制、流处理和环境变量设置,开发者可以更轻松地集成和管理外部进程。在实际应用中,合理使用这些特性可以显著提升应用程序的稳定性和可维护性。 通过以上示例,相信你已经对 Apache Commons Exec 有了基本了解和实践经验。下一章节我们就使用 Apache Commons Exec 自动化脚本执行实现 MySQL 数据库备份,让大家有更深入的理解。
有些场景下需要在java中执行Bat命令或者Shell命令,如使用wkhtmltopdf生成pdf报表等,这时可以借助apachecommons-exec,指定ExecuteWatchdog 可以完整控制整个执行声明周期,不会产生失控进程。 org.apache.commons commons-exec
https://www.csdn.net/tags/MtzaEg0sMzcyNzctYmxvZwO0O0OO0O0O.html 环境变量——bash shell使用环境变量来存储系统相关数据,并允许将数据存储在内存中。 环境变量分为:全局环境变量 本地环境变量 目录全局环境变量 本地环境变量 设置全局环境变量 删除环境变量 PATH全局环境变量 设置系统环境变量的相关文件(登录、非登录、交互、非交互shell) 一、全局环境变量 在当前shell和子shell都可见 可以用printenv命令查看全局环境变
首先在pom.xml中添加Apache Commons Exec的Maven坐标: <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-exec --> <dependency> <groupId>org.apache.commons</groupId&gt...
这个错误可能是由于构建时出现了一些问题导致的。首先,你需要检查构建过程中的错误日志,以了解具体的错误信息。这可以帮助你确定问题的根本原因。 一些常见的构建错误可能包括:缺少依赖项、语法错误、文件权限问题等。你可以检查这些问题,然后尝试修复它们。 此外,你可以尝试重新安装依赖项并重新构建项目。这有时可以解决构建错误。 最后,如果你无法解决问题,可以考虑寻求更高级的支持,例如咨询开发人员或向开发社区寻求帮助。
安装cri-dockerd的时候,注意修改完配置项ExecStart之后 重新运行, systemctl daemon-reload #重载unit配置文件 systemctl start docker #启动Docker systemctl enable docker.service #设置开机自启 才能保证服务生效,才能正常启动cri-dockerd