Java HTTP服务无法获取shell脚本启动的JAR程序的标准输出
问题原因
- ProcessBuilder调用参数错误
你当前代码中构造ProcessBuilder时传入的参数是"bash", cmd,其中cmd是拼接了参数的完整命令字符串/path/to/script/script.sh something。这种写法下,bash会把整个cmd字符串当成一个单独的脚本文件名去查找,而不是把something作为参数传给脚本,最终导致脚本执行失败,没有正常输出。 - 未消费子进程错误流导致进程阻塞
子进程运行过程中如果产生错误输出(比如找不到脚本、找不到JAR包等报错),会写入stderr缓冲区。如果你的代码不主动消费stderr的内容,缓冲区满了之后子进程会被系统阻塞挂起,永远不会执行完成,自然也读不到stdout的输出。 - 路径上下文不一致
你在终端测试脚本时的工作目录,和Java HTTP服务运行时的工作目录不一定相同。如果JAR包用的是相对路径,脚本运行时会找不到JAR文件,执行报错,而你没捕获错误信息自然无法感知。
解决方案
1. 修正ProcessBuilder调用逻辑
有两种正确的传参方式可选:
- 方式一:拆分命令参数,每个参数单独传入
ProcessBuilder builder = new ProcessBuilder("bash", "/path/to/script/script.sh", req);
- 方式二:通过
bash -c执行完整命令串
ProcessBuilder builder = new ProcessBuilder("bash", "-c", cmd);
2. 合并标准输出与错误流,避免进程阻塞
开启错误流合并,让stderr的内容也能被你读取,既可以避免缓冲区满阻塞,也方便排查报错:
// 启动进程前添加这一行 builder.redirectErrorStream(true); Process p = builder.start();
3. 增加进程等待逻辑,确认执行结果
添加进程等待逻辑,通过退出码判断子进程是否正常执行完成:
// 读取输出前先等待进程执行结束 int exitCode = p.waitFor(); System.out.println("子进程退出码:" + exitCode); // 正常退出返回0,非0代表执行出错
4. 修正脚本中的路径和参数写法
脚本里给参数加双引号避免空格问题,JAR包最好写绝对路径,避免工作目录不一致导致找不到文件:
#!/bin/bash # 替换为JAR包的实际绝对路径 java -jar /absolute/path/to/MyJarProgram.jar "$1"
按照以上步骤修改后,就能正常读取到JAR程序的stdout输出了。
内容的提问来源于stack exchange,提问作者Francesco Bertamini
相关产品推荐
相关产品推荐

