Considere el siguiente código:
String commandf = "ls /etc | grep release";
try {
// Execute the command and wait for it to complete
Process child = Runtime.getRuntime().exec(commandf);
child.waitFor();
// Print the first 16 bytes of its output
InputStream i = child.getInputStream();
byte[] b = new byte[16];
i.read(b, 0, b.length);
System.out.println(new String(b));
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
La salida del programa es:
/etc:
adduser.co
Cuando corro desde el shell, por supuesto, funciona como se esperaba:
poundifdef@parker:~/rabbit_test$ ls /etc | grep release
lsb-release
Los internets me dicen que, debido al hecho de que el comportamiento de las tuberías no es multiplataforma, las mentes brillantes que trabajan en la fábrica de Java que produce Java no pueden garantizar que las tuberías funcionen.
¿Cómo puedo hacer esto?
No voy a hacer todo mi análisis utilizando construcciones de Java en lugar de grep
y sed
, porque si quiero cambiar el idioma, me veré obligado a volver a escribir mi código de análisis en ese idioma, lo cual es totalmente prohibido.
¿Cómo puedo hacer que Java realice la canalización y la redirección al llamar a comandos de shell?
java
exec
runtime.exec
poundifdef
fuente
fuente
command | grep foo
, es mucho mejor ejecutarcommand
y filtrar de forma nativa en Java. Hace que su código sea algo más complejo, pero también reduce significativamente el consumo general de recursos y la superficie de ataque.Respuestas:
Escriba un script y ejecute el script en lugar de comandos separados.
La tubería es parte del caparazón, por lo que también puede hacer algo como esto:
fuente
ls
iels -lrt
?android
versión aquí, use/system/bin/sh
en su lugarMe encontré con un problema similar en Linux, excepto que era "ps -ef | grep someprocess".
Al menos con "ls" tiene un reemplazo de Java independiente del lenguaje (aunque más lento). P.ej.:
Con "ps", es un poco más difícil, porque Java no parece tener una API para ello.
Escuché que Sigar podría ayudarnos: https://support.hyperic.com/display/SIGAR/Home
Sin embargo, la solución más simple (como señaló Kaj) es ejecutar el comando canalizado como una matriz de cadenas. Aquí está el código completo:
En cuanto a por qué la matriz de cadenas funciona con tubería, mientras que una sola cadena no ... es uno de los misterios del universo (especialmente si no ha leído el código fuente). Sospecho que es porque cuando a exec se le da una sola cadena, primero la analiza (de una manera que no nos gusta). Por el contrario, cuando a exec se le da una matriz de cadenas, simplemente la pasa al sistema operativo sin analizarla.
En realidad, si nos tomamos un tiempo de un día ajetreado y miramos el código fuente (en http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/ Runtime.java # Runtime.exec% 28java.lang.String% 2Cjava.lang.String []% 2Cjava.io.File% 29 ), encontramos que eso es exactamente lo que está sucediendo:
fuente
Cree un Runtime para ejecutar cada uno de los procesos. Obtenga OutputStream del primer Runtime y cópielo en InputStream desde el segundo.
fuente
La respuesta aceptada de @Kaj es para linux. Este es el equivalente para Windows:
fuente