如何在Java中通过Process对象在已启动的Shell内执行命令
问题:Java启动Docker容器内Bash后无法获取命令输出
问题场景
我通过Java代码启动了一个连接到RabbitMQ Docker容器的Bash Shell:
Process process = Runtime.getRuntime().exec("docker exec rabbitmq bash");
接着尝试在这个Shell里执行rabbitmqctl list_queues命令:
Writer w = new OutputStreamWriter(process.getOutputStream(), "UTF-8"); w.write("rabbitmqctl list_queues\n"); w.flush();
但用以下代码无法获取该命令的输出:
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { System.out.println(line); }
程序没有报错,但如果输入格式错误的命令,能通过错误流收到提示信息:
BufferedReader error = new BufferedReader(new InputStreamReader(process.getErrorStream())); String errorString = error.readLine(); System.out.println("\nError : " + errorString); int exitCode = process.waitFor();
原因分析
- 交互式Shell特性:
docker exec rabbitmq bash启动的是交互式Bash,默认会等待用户输入,非交互式场景下不会主动处理输入并输出结果。 - 输出缓冲问题:非交互式模式下Bash会启用行缓冲或块缓冲,输出不会立即刷新到标准输出流,导致读取代码一直阻塞等待。
- Shell未退出:执行完命令后Bash仍在运行等待下一条指令,输出流不会关闭,读取操作无法结束。
解决方案
方案1:直接执行目标命令(推荐)
跳过启动Bash的步骤,直接通过docker exec执行rabbitmqctl命令,直接获取输出:
Process process = Runtime.getRuntime().exec("docker exec rabbitmq rabbitmqctl list_queues"); // 读取标准输出 BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } // 读取错误输出 BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream())); String errorLine; while ((errorLine = errorReader.readLine()) != null) { System.err.println("Error: " + errorLine); } int exitCode = process.waitFor(); System.out.println("Exit code: " + exitCode);
方案2:通过Bash执行(需调整)
让Bash执行完命令后立即退出,同时关闭输出缓冲:
Process process = Runtime.getRuntime().exec("docker exec rabbitmq bash -c 'rabbitmqctl list_queues'"); // 读取输出和错误流的代码同上
或者通过输入流传递命令时,加上退出指令并强制关闭缓冲:
Process process = Runtime.getRuntime().exec("docker exec rabbitmq bash"); Writer w = new OutputStreamWriter(process.getOutputStream(), "UTF-8"); // 用stdbuf关闭输出缓冲,执行命令后退出Shell w.write("stdbuf -o0 rabbitmqctl list_queues\n"); w.write("exit\n"); w.flush(); w.close(); // 关闭输入流,告知Shell无更多输入 // 读取标准输出 BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } // 读取错误输出 BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream())); String errorLine; while ((errorLine = errorReader.readLine()) != null) { System.err.println("Error: " + errorLine); } int exitCode = process.waitFor();
内容的提问来源于stack exchange,提问作者danilo
相关产品推荐
相关产品推荐

