2010-01-18 6 views
6

Sto chiamando i programmi della riga di comando collegati da pipe. Tutto questo funziona su Linux di sicuro.Java exec() non restituisce il risultato previsto dei comandi collegati delle pipe

mio metodo:

protected String execCommand(String command) throws IOException { 
    String line = null; 
    if (command.length() > 0) { 
     Process child = Runtime.getRuntime().exec(command); 
     InputStream lsOut = child.getInputStream(); 
     InputStreamReader r = new InputStreamReader(lsOut); 
     BufferedReader in = new BufferedReader(r); 

     String readline = null; 
     while ((readline = in.readLine()) != null) { 
      line = line + readline; 
     } 
    } 

    return line; 
} 

Se sto chiamando qualche file cat | grep asd, sto ottenendo il risultato atteso. Ma non tutti i comandi funzionano correttamente. Per esempio con questo:

cat /proc/cpuinfo | wc -l 

o questo:

cat /proc/cpuinfo | grep "model name" | head -n 1 | awk -F":" '{print substr($2, 2, length($2))} 

il metodo ritorna null. Immagino che questo problema dipenda dai comandi di formattazione dell'output come head, tail, wc, ecc. Come posso aggirare questo problema e ottenere il risultato finale dell'output?

+1

Useless (usa * 3) di 'cat'. –

+0

@Dennis - anzi. Ben individuato! –

+0

@Bobby Ho provato, questo non aiuta. – Pawka

risposta

2

Ancora non è stata trovata una soluzione adeguata per eseguire i comandi di piping con Runtime.exec, ma ha trovato una soluzione alternativa. Ho semplicemente scritto questi script per separare i file bash. Quindi Runtime.exec chiama questi script di bash e ottiene i risultati previsti.

+0

Questa è l'unica soluzione che ho trovato tramite google. Non puoi accettare la tua risposta? Comunque, grazie molte. –

+0

Sembra che io possa :-) – Pawka

8

La pipe (come il reindirizzamento, o >) è una funzione della shell, pertanto l'esecuzione direttamente da Java non funzionerà. Hai bisogno di fare qualcosa di simile:

/bin/sh -c "your | piped | commands | here" 

che esegue un processo shell con la linea di comando (tra cui tubi) specificato dopo il -c (tra virgolette).

Si noti inoltre che si deve consumare stdout e stderrconcomitanza, altrimenti il ​​processo generato bloccherà in attesa che il processo di consumare l'uscita (o gli errori). Maggiori informazioni here.

+0

Thx per risposta ma questo ancora non risolve il problema. – Pawka

2

Chiunque utilizzi Runtime.exec deve leggere this.

0

La cosa quick-and-dirty da fare sarebbe:

command = "/bin/sh -c '" + command.replaceAll("'", "'\''") + "'" 

Normalmente, si dovrà fare attenzione per l'iniezione di shell (cioè qualcuno si intrufola "; rm -rf /;" nel comando). Ma questo è solo un problema se parte del comando può essere fornita da qualche altro input dell'utente.

L'approccio lento e doloroso sarebbe quello di eseguire il piping Bash da soli in Java. Se percorri questa strada, scoprirai tutti gli wonderful things that Bash gives you che non sono direttamente disponibili da Process.exec (pipe, reindirizzamento, comandi composti, espansione variabile, valutazione aritmetica, ...).

  1. Analizzare il comando per caratteri |. Assicurati di fare attenzione a || e alle stringhe tra virgolette.
  2. Crea un nuovo Process per ogni comando inviato.
  3. Creare Thread s che legge l'output da un comando e lo scrive sull'input del comando successivo.
0

Probabilmente un po 'troppo tardi, ma per gli altri alla ricerca di una soluzione, provare questo ...

String[] cmd = { 
         "/bin/sh", 
         "-c", 
         "cat /proc/cpuinfo | wc -l" 
        }; 

Process process = Runtime.getRuntime().exec(cmd); 

Tutto il meglio ..

Problemi correlati