这就是我正在做的事情:
import org.apache.commons.exec.*;
String cmd = "/bin/sh -c \"echo test\"";
new DefaultExecutor().execute(CommandLine.parse(cmd));
这是输出:
/bin/sh: echo test: command not found
我究竟做错了什么?
这就是我正在做的事情:
import org.apache.commons.exec.*;
String cmd = "/bin/sh -c \"echo test\"";
new DefaultExecutor().execute(CommandLine.parse(cmd));
这是输出:
/bin/sh: echo test: command not found
我究竟做错了什么?
根据常见问题解答“建议使用CommandLine.addArgument()
而不是CommandLine.parse()
”。
所以试试
CommandLine commandLine = new CommandLine("/bin/sh");
commandLine.addArgument("-c");
commandLine.addArgument("echo test", false); // false is important to prevent commons-exec from acting stupid
executor.execute(commandLine);
这个对我有用:-
CommandLine command = new CommandLine("/bin/sh");
command.addArguments(new String[] {
"-c",
"echo 'test'"
},false);
new DefaultExecutor().execute(command);
我可以从 shell 命令行重现您的问题:
# /bin/sh -c '"echo test"'
# /bin/sh: echo test: command not found
我会说你应该尽量不引用命令。
import org.apache.commons.exec.*;
CommandLine commandLine = new CommandLine("abc.sh");
commandLine.addArgument("param1");
final Executor exec = new DefaultExecutor().execute(commandLine);
该命令不起作用,因为 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)));