2011-01-14 17 views
11

Necesito canalizar un argumento de texto al comando stdin de un comando ejecutado con Apache Commons Exec (para los curiosos, el comando es gpg y el argumento es la frase de paso para el almacén de claves; gpg no tiene un argumento para proporcionar la frase de paso explícitamente , solo para aceptarlo de stdin).Cómo canalizar un argumento de cadena a un ejecutable iniciado con Apache Commons Exec?

Además, necesito esto para admitir tanto Linux como Windows.

En un script de shell que haría

cat mypassphrase|gpg --passphrase-fd 

o

type mypassphrase|gpg --passphrase-fd 

pero el tipo no funciona en Windows ya que no es un archivo ejecutable, pero un comando integrado en el comando cmd (interpretado .exe).

El código no funciona (por el motivo anterior) está a continuación. Para generar un caparazón completo para esto es demasiado feo, estaba buscando una solución más elegante. Lamentablemente, existen algunos problemas de incompatibilidad entre la biblioteca BouncyCastle y PGP, por lo que no puedo usar una solución totalmente programática en el tiempo (muy corto) que tengo.

Gracias de antemano.

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

Respuesta

17

No se puede agregar un argumento tubería (|) porque el comando gpg no aceptará eso. Es el intérprete de órdenes (por ejemplo, bash) el que interpreta el conducto y realiza un procesamiento especial al escribir esa línea de comando en el intérprete de comandos.

Puede usar ByteArrayInputStream para enviar datos manualmente a la entrada estándar de un comando (como hace bash cuando ve el |).

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")); 

Este debería ser el equivalente de escribir echo "hello" | sed s/hello/goodbye/ en un (bash) shell (aunque UTF-8 puede ser una codificación más apropiado).

+0

respuesta muy agradable ! ¡Salvó mi día! – BetaRide

0

Hola a ello voy a utilizar una pequeña clase de ayuda como esto: https://github.com/Macilias/Utils/blob/master/ShellUtils.java

básicamente se puede simular que el uso de tubería como se muestra aquí antes sin llamar a la fiesta de antemano:

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; 
} 
Cuestiones relacionadas