Как передать строковый аргумент в исполняемый файл, запущенный с Apache Commons Exec? - PullRequest
11 голосов
/ 14 января 2011

Мне нужно передать текстовый аргумент в stdin команды, запущенной с Apache Commons Exec (для любопытных команда gpg, а аргумент - пароль для хранилища ключей; у gpg нет аргумента для предоставления пароля явно, только чтобы принять его от стандартного ввода).

Кроме того, мне нужно это для поддержки как Linux, так и Windows.

В сценарии оболочки я бы сделал

cat mypassphrase|gpg --passphrase-fd

или

type mypassphrase|gpg --passphrase-fd

, но тип не работает в 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);

Ответы [ 2 ]

17 голосов
/ 20 января 2011

Вы не можете добавить аргумент канала (|), потому что команда gpg не примет это. Это оболочка (например, 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) оболочку (хотя UTF-8 может быть более подходящей кодировкой).

0 голосов
/ 17 октября 2016

Привет, чтобы сделать это, я буду использовать небольшой вспомогательный класс, подобный следующему: 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;
}
...