Команда не работает, потому что commons-exec делает ненужное цитирование всех аргументов, которые имеют пробел или кавычку.
Это ненужное цитирование аргументов контролируется флагом handleQuoting
каждого аргумента.Если вы создаете объект CommandLine
, используя его конструктор и методы addArgument
, вы можете установить этот флаг на false
.
Примерно так:
CommandLine commandLine = new CommandLine("/bin/sh");
commandLine.addArgument("-c");
commandLine.addArgument("echo test", false);
( Theважная часть - false
как второй аргумент addArgument
метода )
И это работает!Но ... неудобно создавать командную строку вручную, а не определять ее в каком-либо файле конфигурации.
CommandLine.parse
всегда устанавливает для флага handleQuoting
значение true!Кто знает, почему ...
Я написал этот небольшой вспомогательный метод, используя отражение, чтобы исправить «плохой» 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)));