如何使用Java执行Shell命令并在执行过程中实时打印输出内容
Java执行Shell命令并实时打印输出实现方案
要实现执行Shell命令时实时输出内容,核心是异步消费进程的输出缓冲区,不能等进程执行完成再统一读取。Java的Process类启动外部进程后,进程的标准输出、错误输出都会写入独立的缓冲区,若缓冲区满且未被消费,进程会进入阻塞状态停止运行,因此必须通过独立线程消费输出流才能拿到实时内容。
完整实现代码
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.List; public class ShellExecutor { public static void main(String[] args) throws IOException, InterruptedException { // 按操作系统匹配命令前缀,示例执行持续ping命令 String os = System.getProperty("os.name").toLowerCase(); List<String> command; if (os.contains("win")) { // Windows下的ping命令配置 command = List.of("cmd.exe", "/c", "ping -t www.baidu.com"); } else { // Linux/macOS下的ping命令配置 command = List.of("/bin/sh", "-c", "ping www.baidu.com"); } // 构建进程,推荐用ProcessBuilder替代旧的Runtime.exec() ProcessBuilder processBuilder = new ProcessBuilder(command); // 可配置合并错误输出到标准输出,简化流消费逻辑,也可以单独消费错误流 processBuilder.redirectErrorStream(true); Process process = processBuilder.start(); // 启动独立线程消费输出流,实现实时打印 new Thread(() -> { try (BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) { String line; // 逐行读取内容,读到后直接打印不需要缓存 while ((line = reader.readLine()) != null) { System.out.println("实时输出:" + line); } } catch (IOException e) { e.printStackTrace(); } }).start(); // 等待命令执行完成,0为正常退出码 int exitCode = process.waitFor(); System.out.println("命令执行结束,退出码:" + exitCode); } }
关键注意点
- 若需要单独处理错误输出,不要开启
redirectErrorStream(true),单独再起一个线程消费process.getErrorStream()即可,避免两个流缓冲区交叉阻塞 - 消费流时建议显式指定编码,避免不同操作系统默认编码不一致导致输出乱码
- 若需要中途终止命令执行,直接调用
process.destroy()方法即可销毁正在运行的进程 - 如果命令参数包含空格,直接传入字符串列表构造命令即可,不要用
split(" ")拆分,避免参数拆分错误
内容的提问来源于stack exchange,提问作者Anas Elgarhy
相关产品推荐
相关产品推荐

