Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pipe a string argument to an executable launched with Apache Commons Exec?

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);
like image 882
wishihadabettername Avatar asked Jan 14 '11 20:01

wishihadabettername


1 Answers

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).

like image 111
Patrick Avatar answered Oct 01 '22 10:10

Patrick