如何在Java ProcessBuilder中实现输入重定向?
实现Linux
cat << END > output 等效的Java ProcessBuilder功能 问题背景
我已经通过Java ProcessBuilder实现了将Linux cat命令的输出重定向到文件,代码如下:
// read x.txt with cat and redirect the output to output.txt public static void main (String args []) throws Exception { List <String> params = new ArrayList <String> (); params.add ("cat"); params.add ("x.txt"); ProcessBuilder pb = new ProcessBuilder (params); pb.redirectOutput (new File ("output.txt")); Process p = pb.start (); p.waitFor (3, TimeUnit.SECONDS); System.out.println ("exit="+p.exitValue()); }
现在希望实现类似Linux中cat << END > output的Here Document输入重定向功能,但尝试的代码执行后返回状态码1(成功应为0)或无法结束:
public static void main (String args []) throws Exception { List <String> params = new ArrayList <String> (); params.add ("cat"); params.add ("/dev/stdin"); params.add ("<<"); params.add ("END"); ProcessBuilder pb = new ProcessBuilder (params); pb.redirectOutput (new File ("output.txt")); Process p = pb.start (); OutputStream os = p.getOutputStream (); os.write ("\nblabla\nEND\n".getBytes ()); p.waitFor (3, TimeUnit.SECONDS); System.out.println ("exit="+p.exitValue()); }
错误原因
<< END是Shell的Here Document重定向语法,并不是cat命令的合法参数。直接把<<和END传给cat时,cat会将它们当作要读取的文件名,而这些文件实际不存在,因此cat会报错返回状态码1;同时cat会一直等待读取不存在的文件,导致进程无法正常结束。
正确实现方案
方案1:通过Shell执行完整命令
直接调用Shell(如bash)来解析包含Here Document的命令,让Shell处理重定向逻辑:
public static void main(String args[]) throws Exception { List<String> params = new ArrayList<>(); params.add("bash"); params.add("-c"); // 将完整的Shell命令作为参数传递,包含Here Document内容 params.add("cat << END > output.txt\nblabla\nEND"); ProcessBuilder pb = new ProcessBuilder(params); Process p = pb.start(); boolean isFinished = p.waitFor(3, TimeUnit.SECONDS); if (isFinished) { System.out.println("exit=" + p.exitValue()); } else { p.destroy(); System.out.println("进程超时终止"); } }
方案2:直接向cat的标准输入写入内容
cat命令在不带任何参数时,默认会读取标准输入。因此可以直接向Process的输出流(对应cat的标准输入)写入内容,写完后关闭流告知cat输入结束:
public static void main(String args[]) throws Exception { List<String> params = new ArrayList<>(); params.add("cat"); // 无参数时cat默认读取标准输入 ProcessBuilder pb = new ProcessBuilder(params); pb.redirectOutput(new File("output.txt")); Process p = pb.start(); // 使用try-with-resources自动关闭输出流,告知cat输入结束 try (OutputStream os = p.getOutputStream()) { os.write("blabla\n".getBytes()); } boolean isFinished = p.waitFor(3, TimeUnit.SECONDS); if (isFinished) { System.out.println("exit=" + p.exitValue()); } else { p.destroy(); System.out.println("进程超时终止"); } }
两种方案对比:
- 方案1适合需要使用复杂Shell语法的场景,依赖Shell进程解析命令;
- 方案2更轻量,直接与
cat进程交互,无需启动额外的Shell进程。
内容的提问来源于stack exchange,提问作者chris01
相关产品推荐
相关产品推荐

