使用 /bin/bash 从 Java 运行时 exec() 重定向

Redirecs with /bin/bash from Java Runtime exec()

我正在尝试在 Ubuntu 14.04

上使用 java.lang.Runtimeexec() 方法执行的命令中使用重定向
public static void main(String[] args) throws IOException, Exception {
    Runtime runtime = Runtime.getRuntime();
    String command = "echo bla > bla.txt";
    System.out.println("Command : " + command);
    Process process = runtime.exec(command);
    printLines(" stdout", process.getInputStream());
    printLines("  error", process.getErrorStream());
    process.waitFor();
    System.out.println("ExitValue : " + process.exitValue());
}

private static void printLines(String name, InputStream ins) throws Exception {
    try(Stream<String> lines = new BufferedReader(new InputStreamReader(ins)).lines()) {
        lines.forEach(line -> System.out.println(name + " : " + line));
    }
}

输出为:

Command : echo bla > bla.txt
 stdout : bla > bla.txt
ExitValue : 0

所以 bla > bla.txt 被写入 stdout 但当然没有重定向到 bla.txt.

也许 shell 重定向在简单的 exec() 中是不可能的。

所以我尝试将 command = "/bin/bash -c 'echo bla > bla.txt'" 更改为使用整个 echo 并作为参数重定向到 /bin/bash

有了这个我得到了结果:

Command : /bin/bash -c 'echo bla > bla.txt'
  error : bla: -c: line 0: unexpected EOF while looking for matching `''
  error : bla: -c: line 1: syntax error: unexpected end of file
ExitValue : 1

当然 /bin/bash -c 'echo bla > bla.txt'在 Ubuntu 上工作正常并创建所需的文件。

我找不到可以设置单引号的地方来获得令人满意的结果,而且我还尝试了各种转义字符来转义空格或重定向(>)。

如果我使用像

这样的命令数组就可以了
String cmdArray[] = {"/bin/bash", "-c", "echo bla > bla.txt"};
Process process = runtime.exec(cmdArray);

,但它必须是单个字符串,因为整个命令必须在其他地方构建。

我当然知道

我很好奇为什么这不起作用。

原因是 exec 使用简单的 StringTokenizer 和任何白色 space 作为分隔符来解析实际命令。因此它是便携的,因为当你传递一些复杂的东西时它确实无处工作:-)

您选择的解决方法是正确的、可移植的,而且最重要的是最安全,因为如果命令包含例如引号等,您不需要转义。

String command = "echo bla > bla.txt";
Process process = runtime.exec(command);

命令中的 > blah.txt 文本是 shell 重定向标准输出的语法。它由 shell 实现,例如 shbash

Runtime.exec() 不使用 shell 到 运行 命令。 here and here 描述了它启动命令的方式。基本上,它使用自己的逻辑将命令字符串拆分为空格处的参数,然后直接执行生成的命令。

如果要调用应解释为 shell 命令的命令,则需要显式调用 shell:

String[] command = { "/bin/bash", "-c", "echo bla > bla.txt" };
Process process = runtime.exec(command);