当前位置: 首页 > news >正文

java——执行linux/cmd命令

在Java中执行命令行命令可以通过Runtime.exec()ProcessBuilder实现。以下是两种方法的详细说明和示例代码:


1. 使用 Runtime.exec()

适用于简单场景,但需手动处理输入/输出流。

try {
    // 执行命令(参数以数组形式传递,避免空格问题)
    Process process = Runtime.getRuntime().exec(new String[]{"ping", "-n", "3", "127.0.0.1"});
    
    // 读取标准输出流
    BufferedReader inputReader = new BufferedReader(
        new InputStreamReader(process.getInputStream())
    );
    // 读取错误流
    BufferedReader errorReader = new BufferedReader(
        new InputStreamReader(process.getErrorStream())
    );
    
    // 打印输出和错误信息
    String line;
    while ((line = inputReader.readLine()) != null) {
        System.out.println("输出: " + line);
    }
    while ((line = errorReader.readLine()) != null) {
        System.out.println("错误: " + line);
    }
    
    // 等待命令执行完成并获取退出码
    int exitCode = process.waitFor();
    System.out.println("退出码: " + exitCode);
    
} catch (IOException | InterruptedException e) {
    e.printStackTrace();
}

2. 使用 ProcessBuilder

更灵活,支持错误流合并、工作目录设置等。

try {
    // 构建命令及参数
    ProcessBuilder pb = new ProcessBuilder();
    pb.command("ping", "-n", "3", "127.0.0.1");
    
    // 合并标准输出和错误流(简化处理)
    pb.redirectErrorStream(true);
    
    // 设置工作目录(可选)
    // pb.directory(new File("path/to/dir"));
    
    // 启动进程
    Process process = pb.start();
    
    // 读取输出流
    BufferedReader reader = new BufferedReader(
        new InputStreamReader(process.getInputStream())
    );
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
    
    // 等待命令结束
    int exitCode = process.waitFor();
    System.out.println("退出码: " + exitCode);
    
} catch (IOException | InterruptedException e) {
    e.printStackTrace();
}

关键点说明

  1. 参数传递
    将命令和参数拆分为字符串数组,避免空格导致的解析错误。

  2. 流处理

    • 必须读取输出流:否则进程可能因缓冲区满而阻塞。
    • 多线程处理:若需同时处理标准输出和错误流,可使用多线程(如示例1)。
    • 合并流:通过redirectErrorStream(true)合并错误流到标准输出,简化代码(如示例2)。
  3. 超时控制
    使用waitFor(long timeout, TimeUnit unit)(Java 8+)防止无限等待:

    if (!process.waitFor(30, TimeUnit.SECONDS)) {
        process.destroy(); // 强制终止进程
        System.out.println("命令执行超时");
    }
    
  4. 跨平台兼容性

    • Windows可能需要cmd /c前缀:
      pb.command("cmd", "/c", "dir");
      
    • 根据系统属性调整命令:
      String os = System.getProperty("os.name").toLowerCase();
      if (os.contains("win")) {
          pb.command("cmd", "/c", "mycommand");
      } else {
          pb.command("sh", "-c", "mycommand");
      }
      
  5. 资源释放
    finally块中关闭流或使用Try-with-Resources(需自定义处理)。

乱码


在Java中读取命令行输出时出现中文乱码,通常是因为系统默认编码与命令行输出的编码不一致(例如,Windows的cmd默认使用GBK编码,而程序可能使用UTF-8)。以下是解决方案及优化后的代码:


原因分析

  • Windows命令行编码:默认使用GBK(对应代码页CP936)。
  • Linux/macOS终端编码:通常为UTF-8
  • Java程序默认编码:可能与系统编码不同(例如,IDE运行时默认UTF-8)。

解决方案

1. 显式指定字符编码

在创建InputStreamReader时,明确指定与命令行输出一致的编码(如Windows下使用GBK)。

// Windows示例:使用GBK编码读取
BufferedReader inputReader = new BufferedReader(
    new InputStreamReader(process.getInputStream(), "GBK")
);

// Linux/macOS示例:使用UTF-8
BufferedReader inputReader = new BufferedReader(
    new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8)
);

2. 自动检测系统编码(推荐)

动态判断操作系统类型,自动选择编码:

import java.nio.charset.Charset;

public class CharsetHelper {
    // 获取命令行输出的默认编码(Windows为GBK,其他系统为UTF-8)
    public static Charset getConsoleCharset() {
        String os = System.getProperty("os.name").toLowerCase();
        if (os.contains("win")) {
            return Charset.forName("GBK");
        } else {
            return StandardCharsets.UTF_8;
        }
    }
}

// 使用示例:
Charset charset = CharsetHelper.getConsoleCharset();
BufferedReader inputReader = new BufferedReader(
    new InputStreamReader(process.getInputStream(), charset)
);

完整优化代码示例(以ProcessBuilder为例)


import org.apache.commons.lang3.StringUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) {
        //System.out.println("Hello, World!");
        RuntimeExec("ping 127.0.0.1");
        RuntimeExec2("ping www.baidu.com");
    }

    public static void RuntimeExec(String cmd) {
        try {
            if (StringUtils.isBlank(cmd)) {
                return;
            }
            String[] cmds = cmd.split(" ");
            // 出去空格
            for (int i = 0; i < cmds.length; i++)
                cmds[i] = cmds[i].trim();
            // 执行命令(参数以数组形式传递,避免空格问题)
            Process process = Runtime.getRuntime().exec(cmds); /*, null, new File("C:\\Windows\\System32")*/  //new String[]{"ping", "-n", "3", "127.0.0.1"});

            // 读取标准输出流
            BufferedReader inputReader = new BufferedReader(
                    new InputStreamReader(process.getInputStream(), "GB2312")
            );
            // 读取错误流
            BufferedReader errorReader = new BufferedReader(
                    new InputStreamReader(process.getErrorStream(), "GB2312")
            );

            // 打印输出和错误信息
            String line;
            while ((line = inputReader.readLine()) != null) {
                System.out.println("out: " + line);
            }
            while ((line = errorReader.readLine()) != null) {
                System.out.println("err: " + line);
            }

            // 等待命令执行完成并获取退出码
            int exitCode = process.waitFor();
            System.out.println("out: " + exitCode);

        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void RuntimeExec2(String cmd) {
        try {
            if (StringUtils.isBlank(cmd)) {
                return;
            }
            String[] cmds = cmd.split(" ");
            // 出去空格
            for (int i = 0; i < cmds.length; i++)
                cmds[i] = cmds[i].trim();
            // 构建命令及参数
            ProcessBuilder pb = new ProcessBuilder();
            pb.command(cmds);

            // 合并标准输出和错误流(简化处理)
            pb.redirectErrorStream(true);

            // 设置工作目录(可选)
            // pb.directory(new File("path/to/dir"));

            // 启动进程
            Process process = pb.start();

            // 读取输出流
            BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream(),"GB2312")
            );
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }

            // 等待命令结束
            int exitCode = process.waitFor();
            System.out.println("退出码: " + exitCode);

        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

其他注意事项

  1. 强制命令行使用UTF-8(Windows)
    在Windows中,可以通过/U参数让cmd输出UTF-8编码:

    pb.command("cmd", "/U", "/c", "chcp 65001 && ping -n 3 127.0.0.1");
    

    此时需将编码设置为UTF-8

    new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8)
    
  2. 验证命令行编码

    • Windows下运行chcp命令查看活动代码页:
      • 936GBK
      • 65001UTF-8
    • 根据实际代码页调整编码设置。
  3. 统一环境编码
    在程序启动时指定JVM编码(如-Dfile.encoding=UTF-8),但需确保与命令行编码一致。


总结

  • 简单命令:推荐ProcessBuilder,代码更简洁。
  • 复杂场景(如交互式输入、大量输出):结合多线程处理流,避免阻塞。
  • 注意事项:正确处理参数、流、超时及跨平台问题。
http://www.dtcms.com/a/40856.html

相关文章:

  • SE注意力机制详解:从原理到应用,全面解析Squeeze-and-Excitation模块
  • JWT+redis实现三大令牌管理方案深度解析
  • DeepSeek 2月27日技术突破:三大核心功能解析与行业影响
  • AI问答-供应链管理:排队模型M/D/5/100/m/FCFS代表的含义是什么
  • ProfiNet转EtherCAT 网关:助力工业设备 “对话”的神奇纽带
  • 一文5分钟掌握基于JWT的模拟登录爬取实战
  • STR初识
  • IP、网关、子网掩码、DNS 之间的关系详解
  • 升级TTSDK抖音小游戏banner广告接入
  • ios swift摄像头画中画技术的探索与突破
  • Elasticsearch:使用阿里云 AI 服务进行嵌入和重新排名
  • 8.Dashboard的导入导出
  • VSCode轻松调试运行.Net 8.0 Web API项目
  • 如何使用豆包AI来快速提升编程能力?
  • 自然语言处理:稀疏向量表示
  • ASP.NET MVC AJAX 文件上传
  • OpenCV计算摄影学(6)高动态范围成像(HDR imaging)
  • 网站漏洞查找渗透测试攻防演练
  • 【easy视频 | day01】项目了解 + 登录注册 + 使用 token 作为客户端请求令牌
  • MySQL—Keepalived+MySQL双主复制实现MySQL高可用
  • 基于Rook的Ceph云原生存储部署与实践指南(上)
  • 第九章:多模态大语言模型
  • NL2SQL的应用-长上下文模型在处理NL2SQL任务时,相较于传统模型,有哪些显著的优势
  • CSS 日常开发常用属性总结
  • 数据结构:Top-K问题详解
  • AIGC和搜索引擎的异同
  • 在VSCode中使用MarsCode AI最新版本详解
  • drupal的导入的item-list在哪里查看
  • Java 面试题 20250227
  • 工业AR眼镜的‘芯’动力:FPC让制造更智能【新立电子】