如何向ProcessBuilder发送字符串输入并通过线程实现CLI自动化
实现代码
你需要分别处理进程的输入写入、输出读取逻辑,两者要放在不同线程避免阻塞,以下是可直接运行的实现:
import java.io.*; class Envir { private Process process; private BufferedWriter commandWriter; private Thread outputReaderThread; public void run() throws IOException { ProcessBuilder builder = new ProcessBuilder("bash"); builder.redirectInput(ProcessBuilder.Redirect.PIPE); builder.redirectOutput(ProcessBuilder.Redirect.PIPE); builder.redirectErrorStream(true); // 合并错误流到输出流,不用单独读错误流 process = builder.start(); // 初始化命令输入流,用来给bash发命令 commandWriter = new BufferedWriter(new OutputStreamWriter(process.getOutputStream())); // 启动独立线程读取bash的输出内容,避免缓冲区满导致进程阻塞 outputReaderThread = new Thread(() -> { try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { String line; while ((line = reader.readLine()) != null) { // 这里可以自定义输出处理逻辑,比如打印、解析返回结果 System.out.println("[Bash Output] " + line); } } catch (IOException e) { if (!process.isAlive()) { System.out.println("进程已退出,输出读取结束"); } else { e.printStackTrace(); } } }); outputReaderThread.start(); } // 对外暴露的发命令方法 public void sendCommand(String command) throws IOException { if (commandWriter == null || !process.isAlive()) { throw new IllegalStateException("bash进程未启动"); } commandWriter.write(command); commandWriter.newLine(); // bash按行解析命令,必须加换行才会执行 commandWriter.flush(); // 强制刷出缓冲区,命令立刻发送 } // 销毁进程和释放资源 public void stop() throws InterruptedException, IOException { sendCommand("exit"); // 正常退出bash process.waitFor(); commandWriter.close(); outputReaderThread.join(); process.destroy(); } public static void main(String[] args) throws Exception { Envir envir = new Envir(); envir.run(); // 测试执行命令 envir.sendCommand("env python3 --version"); envir.sendCommand("echo 测试命令执行"); envir.sendCommand("ls -l"); // 等待3秒获取所有输出后退出 Thread.sleep(3000); envir.stop(); } }
核心逻辑说明
- 命令写入逻辑:通过
Process.getOutputStream()获取bash进程的标准输入流,包装为BufferedWriter后即可按行发送自定义命令,每次发送必须加换行符并执行flush()操作,否则命令会停留在缓冲区不被执行。 - 输出读取逻辑:必须单独开线程读取进程的输出流,因为流读取是阻塞操作,如果放在主线程会卡住命令发送逻辑;如果不及时读取输出,缓冲区占满后bash进程会直接阻塞,不再执行任何命令。
- 资源回收:执行完成后先发送
exit命令正常退出bash,再等待进程结束、关闭所有流、销毁进程,避免出现僵尸进程。
注意事项
- 如果要和交互式CLI(比如python REPL、mysql命令行)交互,可以在发送命令后增加输出匹配逻辑,检测到指定特征返回后再发下一条命令,避免命令发送过快导致执行异常。
- 可以根据需求修改输出读取线程的逻辑,比如把输出存到队列里供其他业务逻辑消费。
内容的提问来源于stack exchange,提问作者user13335570
相关产品推荐
相关产品推荐

