使用 /bin/bash 从 Java 运行时 exec() 重定向
Redirecs with /bin/bash from Java Runtime exec()
我正在尝试在 Ubuntu 14.04
上使用 java.lang.Runtime
的 exec()
方法执行的命令中使用重定向
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 实现,例如 sh
或 bash
。
Runtime.exec()
不使用 shell 到 运行 命令。 here and here 描述了它启动命令的方式。基本上,它使用自己的逻辑将命令字符串拆分为空格处的参数,然后直接执行生成的命令。
如果要调用应解释为 shell 命令的命令,则需要显式调用 shell:
String[] command = { "/bin/bash", "-c", "echo bla > bla.txt" };
Process process = runtime.exec(command);
我正在尝试在 Ubuntu 14.04
上使用java.lang.Runtime
的 exec()
方法执行的命令中使用重定向
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 实现,例如 sh
或 bash
。
Runtime.exec()
不使用 shell 到 运行 命令。 here and here 描述了它启动命令的方式。基本上,它使用自己的逻辑将命令字符串拆分为空格处的参数,然后直接执行生成的命令。
如果要调用应解释为 shell 命令的命令,则需要显式调用 shell:
String[] command = { "/bin/bash", "-c", "echo bla > bla.txt" };
Process process = runtime.exec(command);