如何通过管道将字符串参数传递给使用 Apache Commons Exec 启动的可执行文件?

发布于 2024-10-12 12:41:29 字数 1200 浏览 5 评论 0原文

我需要将文本参数通过管道传输到使用 Apache Commons Exec 启动的命令的标准输入(出于好奇,该命令是 gpg,参数是密钥库的密码;gpg 没有显式提供密码的参数,仅从标准输入接受它)。

另外,我需要这个来支持Linux和Windows。

在 shell 脚本中,我会执行

cat mypassphrase|gpg --passphrase-fd

or

type mypassphrase|gpg --passphrase-fd

但 type 在 Windows 上不起作用,因为它不是可执行文件,而是内置于命令解释 (cmd.exe) 中的命令。

无法运行的代码(由于上述原因)如下。为此生成整个外壳太丑陋了,我一直在寻找更优雅的解决方案。不幸的是,BouncyCastle 库和 PGP 之间存在一些不兼容问题,因此我无法在(非常短的)时间内使用完全编程的解决方案。

提前致谢。

CommandLine cmdLine = new CommandLine("type");
cmdLine.addArgument(passphrase);
cmdLine.addArgument("|");
cmdLine.addArgument("gpg");
cmdLine.addArgument("--passphrase-fd");
cmdLine.addArgument("0");
cmdLine.addArgument("--no-default-keyring");
cmdLine.addArgument("--keyring");
cmdLine.addArgument("${publicRingPath}");
cmdLine.addArgument("--secret-keyring");
cmdLine.addArgument("${secretRingPath}");
cmdLine.addArgument("--sign");
cmdLine.addArgument("--encrypt");
cmdLine.addArgument("-r");
cmdLine.addArgument("recipientName");
cmdLine.setSubstitutionMap(map);
DefaultExecutor executor = new DefaultExecutor();
int exitValue = executor.execute(cmdLine);

I need to pipe a text argument to the stdin of a command launched with Apache Commons Exec (for the curious, the command is gpg and the argument is the passphrase to the keystore; gpg does not have an argument to provide the passphrase explicitly, only to accept it from stdin).

In addition, I need this to support both Linux and Windows.

In a shell script I'd do

cat mypassphrase|gpg --passphrase-fd

or

type mypassphrase|gpg --passphrase-fd

but type doesn't work on Windows as it's not an executable but a command built into the command interpreted (cmd.exe).

The code not working (for the above reason) is below. To spawn an entire shell for this is too ugly, I was looking for a more elegant solution. Unfortunately, there are some incompatibility problems between the BouncyCastle library and PGP so I cannot use a fully programmatic solution in the (very short) time I have.

Thanks in advance.

CommandLine cmdLine = new CommandLine("type");
cmdLine.addArgument(passphrase);
cmdLine.addArgument("|");
cmdLine.addArgument("gpg");
cmdLine.addArgument("--passphrase-fd");
cmdLine.addArgument("0");
cmdLine.addArgument("--no-default-keyring");
cmdLine.addArgument("--keyring");
cmdLine.addArgument("${publicRingPath}");
cmdLine.addArgument("--secret-keyring");
cmdLine.addArgument("${secretRingPath}");
cmdLine.addArgument("--sign");
cmdLine.addArgument("--encrypt");
cmdLine.addArgument("-r");
cmdLine.addArgument("recipientName");
cmdLine.setSubstitutionMap(map);
DefaultExecutor executor = new DefaultExecutor();
int exitValue = executor.execute(cmdLine);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

别念他 2024-10-19 12:41:29

您无法添加管道参数 (|),因为 gpg 命令不会接受该参数。当您在 shell 中键入命令行时,shell(例如 bash)会解释管道并进行特殊处理。

您可以使用 ByteArrayInputStream 手动将数据发送到命令的标准输入(就像 bash 看到 | 时所做的那样)。

    Executor exec = new DefaultExecutor();

    CommandLine cl = new CommandLine("sed");
            cl.addArgument("s/hello/goodbye/");

    String text = "hello";
    ByteArrayInputStream input =
        new ByteArrayInputStream(text.getBytes("ISO-8859-1"));
    ByteArrayOutputStream output = new ByteArrayOutputStream();

    exec.setStreamHandler(new PumpStreamHandler(output, null, input));
    exec.execute(cl);

    System.out.println("result: " + output.toString("ISO-8859-1"));

这应该相当于输入 echo "hello" | sed s/hello/goodbye/ 进入 (bash) shell(尽管 UTF-8 可能是更合适的编码)。

You cannot add a pipe argument (|) because the gpg command won't accept that. It's the shell (e.g. bash) that interprets the pipe and does special processing when you type that commandline into the shell.

You can use ByteArrayInputStream to manually send data to the standard input of a command (much like bash does when it sees the |).

    Executor exec = new DefaultExecutor();

    CommandLine cl = new CommandLine("sed");
            cl.addArgument("s/hello/goodbye/");

    String text = "hello";
    ByteArrayInputStream input =
        new ByteArrayInputStream(text.getBytes("ISO-8859-1"));
    ByteArrayOutputStream output = new ByteArrayOutputStream();

    exec.setStreamHandler(new PumpStreamHandler(output, null, input));
    exec.execute(cl);

    System.out.println("result: " + output.toString("ISO-8859-1"));

This should be the equivalent of typing echo "hello" | sed s/hello/goodbye/ into a (bash) shell (though UTF-8 may be a more appropriate encoding).

后来的我们 2024-10-19 12:41:29

嗨,要做到这一点,我将使用一个像这样的小助手类: https://github .com/Macilias/Utils/blob/master/ShellUtils.java

基本上,您可以像之前所示那样模拟管道使用情况,而无需事先调用 bash:

public static String runCommand(String command, Optional<File> dir) throws IOException {
    String[] commands = command.split("\\|");
    ByteArrayOutputStream output = null;
    for (String cmd : commands) {
        output = runSubCommand(output != null ? new ByteArrayInputStream(output.toByteArray()) : null, cmd.trim(), dir);
    }
    return output != null ? output.toString() : null;
}

private static ByteArrayOutputStream runSubCommand(ByteArrayInputStream input, String command, Optional<File> dir) throws IOException {
    final ByteArrayOutputStream output = new ByteArrayOutputStream();
    CommandLine cmd = CommandLine.parse(command);
    DefaultExecutor exec = new DefaultExecutor();
    if (dir.isPresent()) {
        exec.setWorkingDirectory(dir.get());
    }
    PumpStreamHandler streamHandler = new PumpStreamHandler(output, output, input);
    exec.setStreamHandler(streamHandler);
    exec.execute(cmd);
    return output;
}

Hi to do this i will use a little helper class like this: https://github.com/Macilias/Utils/blob/master/ShellUtils.java

basically you can than simulate the pipe usage like shown here before without calling the bash beforehand:

public static String runCommand(String command, Optional<File> dir) throws IOException {
    String[] commands = command.split("\\|");
    ByteArrayOutputStream output = null;
    for (String cmd : commands) {
        output = runSubCommand(output != null ? new ByteArrayInputStream(output.toByteArray()) : null, cmd.trim(), dir);
    }
    return output != null ? output.toString() : null;
}

private static ByteArrayOutputStream runSubCommand(ByteArrayInputStream input, String command, Optional<File> dir) throws IOException {
    final ByteArrayOutputStream output = new ByteArrayOutputStream();
    CommandLine cmd = CommandLine.parse(command);
    DefaultExecutor exec = new DefaultExecutor();
    if (dir.isPresent()) {
        exec.setWorkingDirectory(dir.get());
    }
    PumpStreamHandler streamHandler = new PumpStreamHandler(output, output, input);
    exec.setStreamHandler(streamHandler);
    exec.execute(cmd);
    return output;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文