该命令不起作用,因为 commons-exec 对所有带有空格或引号的参数进行了不必要的引用。
这种不必要的参数引用由每个参数的handleQuoting 标志控制。如果您使用CommandLine 对象的构造函数和addArgument 方法创建对象,则可以将此标志设置为false。
像这样:
CommandLine commandLine = new CommandLine("/bin/sh");
commandLine.addArgument("-c");
commandLine.addArgument("echo test", false);
(重要的部分是false作为addArgument方法的第二个参数)
而且它有效!但是......手动构建命令行而不是在某个配置文件中定义它是不方便的。
CommandLine.parse 总是将handleQuoting 标志设置为真!谁知道为什么...
我编写了这个使用反射来修复“坏”CommandLine 对象的小辅助方法,该对象是使用CommandLine.parse 创建的。
public static CommandLine fixCommandLine(CommandLine badCommandLine) {
try {
CommandLine fixedCommandLine = new CommandLine(badCommandLine.getExecutable());
fixedCommandLine.setSubstitutionMap(badCommandLine.getSubstitutionMap());
Vector<?> arguments = (Vector<?>) FieldUtils.readField(badCommandLine, "arguments", true);
arguments.stream()
.map(badArgument -> {
try {
return (String) FieldUtils.readField(badArgument, "value", true);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
})
.forEach(goodArgument -> fixedCommandLine.addArgument(goodArgument, false));
return fixedCommandLine;
} catch (Exception e) {
logger.error("Cannot fix bad command line", e);
return badCommandLine;
}
}
它只是克隆给定的CommandLine,将每个参数的handleQuoting 标志设置为false。
方法FieldUtils.readField 来自commons-lang3 库,但如果需要,您可以使用普通反射。
它允许解析命令行并仍然成功执行它。
String cmd = "/bin/sh -c 'echo test'";
new DefaultExecutor().execute(fixCommandLine(CommandLine.parse(cmd)));