2012-01-05 4 views
9

È possibile passare l'output di un processo creato da ProcessBuilder a un altro processo creato da un altro ProcessBuilder? Per esempio, se sto cercando di eseguire questo comando shell:output piping di ProcessBuilder su un altro ProcessBuilder

ls | grep build.xml 

come devo fare con ProcessBuilder?

come @erdinc suggerito, ho provato questo:

Process process = Runtime.getRuntime().exec("ls"); 
InputStream is = process.getInputStream(); 
byte[] buf = new byte[1000]; 
is.read(buf); 
String parameter = new String(buf); 
System.out.println("grep build " + parameter); 

Process proc2 = Runtime.getRuntime().exec("grep build " + parameter); 
InputStream is2 = proc2.getInputStream(); 
byte[] buf2 = new byte[1000]; 
is2.read(buf2); 
String result = new String(buf2); 
System.out.println("proc2 result: " + result); 

ma produce risultati diversi confrontare quando si esegue lo script direttamente nel guscio. Dove ho sbagliato?

Risolto: Si prega di vedere la soluzione di Philipp Wendler

risposta

6

Il problema con la soluzione che abbiamo è che si legge solo i primi 1000 byte dal output di ls e li passa a grep. Dato che non si conosce la quantità di output di ls prima, è necessario leggerlo iterativamente fino a quando non è esaurito.

Ecco una soluzione che utilizza BufferedReader, che invierà ogni riga di output a grep:

Process lsProcess = Runtime.getRuntime().exec("ls"); 
BufferedReader lsOutput = new BufferedReader(new InputStreamReader(lsProcess.getInputStream())); 
Process grepProcess = Runtime.getRuntime().exec("grep build.xml"); 
BufferedWriter grepInput = new BufferedWriter(new OutputStreamWriter(grepProcess.getOutputStream())); 

String line; 
// read each line from ls until there are no more 
while ((line = lsOutput.readLine()) != null) { 
    // and send them to grep 
    grepInput.write(line); 
    grepInput.newLine(); 
} 

// send end-of-file signal to grep so it will terminate itself 
grepInput.close(); 

Naturalmente è necessario aggiungere l'appropriata gestione degli errori qui. È possibile omettere Reader e Writer e passare gli array byte[] direttamente dall'input allo stream di output se questa soluzione è troppo lenta.

Tuttavia, una soluzione molto migliore sarebbe non usare ls e grep per cercare un file nel filesystem, ma per utilizzare l'API Java appropriata. Ad esempio, se si crea un oggetto File per la directory a cui si è interessati, è possibile utilizzare i vari metodi listFiles per elencare tutti i file in questa directory. Questo metodo è molto più semplice, portatile, meno soggetto a errori e probabilmente più veloce.

+0

la tua soluzione funziona! grazie Philipp: D In realtà userò questo codice per chiamare diverse applicazioni esterne come chasen e moses (strumenti di traduzione automatica). Ls | L'esempio di grep è stato pensato solo per semplificare la domanda, ma grazie per il suggerimento: D Contrassegnerò la domanda risolta e sostituirò la tua soluzione. – ndriks

0

È possibile utilizzare il metodo getInputStream di passare come parametro secondo processo. Codice di esempio;

 process = Runtime.getRuntime().exec("ls"); 
     InputStream is = process.getInputStream(); 
     byte[] buf = new byte[1000]; 
     is.read(buf); 
     String parameter = new String(buf); 
     System.out.println(parameter); 
     Runtime.getRuntime().exec("grep build.xml " + parameter); 
+0

ma come passare il flusso di input "ls" al processo "grep"? Non riesco a trovare il metodo setInputStream in Process. Inoltre può essere fatto con ProcessBuilder? – ndriks

+0

Ho provato la soluzione @erdinc, ma produce risultati diversi rispetto all'esecuzione del comando direttamente nella shell. Ho modificato la domanda per mostrare cosa ho fatto. Per vostra informazione, non sto cercando di eseguire grep con ls risultato come parametro, ma sto provando a reindirizzare il risultato di ls al processo di grep. – ndriks