Java调用Shell命令获取Docker中MySQL输出失败原因排查
问题分析与修复方案
你的Java代码存在三个核心问题,导致无法获取预期输出:
1. inheritIO() 导致无法读取子进程输出
ProcessBuilder.inheritIO()会将子进程的标准输入、输出、错误流直接绑定到当前JVM的控制台流,这意味着子进程的输出会直接打印到控制台,而不会流入process.getInputStream()中。你后续读取这个流时,自然获取不到任何内容,最终rst为空字符串。
2. 缺少MySQL登录用户名参数
你在控制台执行的命令明确指定了-uroot登录用户,但Java代码中的命令仅包含-p123456,未指定用户名。MySQL客户端默认会使用当前操作系统用户名尝试登录,而Docker容器内的MySQL大概率没有对应用户,导致登录失败,没有输出内容。
3. 未处理错误流
即使登录失败,错误信息会输出到标准错误流,但原代码既用inheritIO()接管了流,又未读取错误流,导致你无法看到登录失败的提示信息,难以排查问题。
修复后的代码
修正执行命令的方法
private Pair<Integer, String> execForExitCode(String[] command) { try { Process process = new ProcessBuilder(command).start(); // 读取标准输出 String stdout = new String(process.getInputStream().readAllBytes(), StandardCharsets.UTF_8); // 读取错误输出,用于排查问题 String stderr = new String(process.getErrorStream().readAllBytes(), StandardCharsets.UTF_8); int exitCode = process.waitFor(); // 合并输出与错误信息,方便调试 String rst = stdout.trim() + (!stderr.isEmpty() ? "\n错误信息:" + stderr.trim() : ""); return Pair.of(exitCode, rst); } catch (Exception e) { throw new RuntimeException(e); } }
修正命令数组(添加用户名参数)
String[] cmd = new String[] {"docker", "exec", "my", "mysql", "-uroot", "-p123456", "-e", "select @@report_host\\G"}; Pair<Integer, String> result = this.execForExitCode(cmd); String[] lines = result.getRight().split("\n"); log.info("getDbReportHost:"); for (String line : lines) { log.info(line); }
内容的提问来源于stack exchange,提问作者Calvin_Z
相关产品推荐
相关产品推荐

