Как передать строковый аргумент в исполняемый файл, запущенный с Apache Commons Exec?
Мне нужно передать текстовый аргумент в stdin команды, запущенной с Apache Commons Exec (для любопытных команда gpg и аргумент - ключевая фраза в хранилище ключей; gpg не имеет аргумента для предоставления кодовой фразы явно, только чтобы принять его из stdin).
Кроме того, мне нужно это для поддержки Linux и Windows.
В оболочке script я бы сделал
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);
Ответы
Ответ 1
Вы не можете добавить аргумент pipe (|
), потому что команда 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 может быть более подходящей кодировкой).
Ответ 2
Привет, я буду использовать небольшой вспомогательный класс следующим образом: 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;
}