【问题标题】:How to execute /bin/sh with commons-exec?如何使用 commons-exec 执行 /bin/sh?
【发布时间】:2011-02-22 15:27:44
【问题描述】:

这就是我正在做的:

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

我做错了什么?

【问题讨论】:

  • 这是什么平台? Linux?是/bin/sh bash 还是破折号,还是一些没有echo 内置的shell?

标签: java apache-commons-exec


【解决方案1】:

根据the FAQ“建议使用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);

【讨论】:

  • 你确定你没有添加任何额外的引号?
  • 阳性。我正在使用您提供的示例。
  • 在这里传递false 很关键。我什至尝试过commandLine.addArgument("\"echo test\""),但我得到了退出代码127,这表明bash 无法执行它。
【解决方案2】:

这个对我有用:-

    CommandLine command = new CommandLine("/bin/sh");
    command.addArguments(new String[] {
            "-c",
            "echo 'test'"
    },false);
    new DefaultExecutor().execute(command);

【讨论】:

  • 不做与问题相同的事情。这将使用参数test 执行/bin/echo,而不是使用参数-cecho test/bin/sh。它们是不同的,因为echo 也内置在/bin/sh 中。
  • @limc 它可以工作,但这并不是让这个特定示例工作的重点。关键是为外部过程提供一个复杂的论据,到目前为止我还做不到..
  • @yegor256:你在标记我之前看过我的更正版本吗?
  • @yegor256:等等,什么复杂的论点?您是否正在尝试做超出echo test 的事情?
  • 我刚刚花了一些时间阅读 commons-exec 的源代码,如果您尽可能不为handleQuoting 参数提供false,它似乎会完全延迟。真的很糟糕的设计,恕我直言。
【解决方案3】:

我可以从 shell 命令行重现您的问题:

# /bin/sh -c '"echo test"'
# /bin/sh: echo test: command not found

我会说你应该尽量不引用命令。

【讨论】:

  • 如何将echotest分组比?
【解决方案4】:

该命令不起作用,因为 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)));

【讨论】:

    【解决方案5】:
    import org.apache.commons.exec.*; 
    
    CommandLine commandLine = new CommandLine("abc.sh");
    commandLine.addArgument("param1"); 
    final Executor exec = new DefaultExecutor().execute(commandLine);
    

    【讨论】:

    • 虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。
    猜你喜欢
    • 2022-11-03
    • 1970-01-01
    • 1970-01-01
    • 2021-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-06
    相关资源
    最近更新 更多