2009-09-11 25 views
80

Sto tentando di eseguire alcuni comandi Linux da Java utilizzando il reindirizzamento (> &) e le pipe (|). In che modo Java può richiamare i comandi csh o bash?Desidero richiamare un comando di shell linux da Java

ho provato ad usare questo:

Process p = Runtime.getRuntime().exec("shell command"); 

ma non è compatibile con i reindirizzamenti o tubi.

+2

'cat' e' csh' non hanno nulla a che fare l'uno con l'altro. – Bombe

+4

Posso capire la domanda per altri comandi, ma per gatto: perché diavolo non leggi semplicemente nel file? – Atmocreations

+7

Tutti sbagliano la prima volta: Java exec() non usa la shell del sistema sottostante per eseguire il comando (come fa notare kts). Il reindirizzamento e le piping sono caratteristiche di una shell reale e non sono disponibili da exec() di Java. – SteveD

risposta

76

exec non esegue un comando nella shell

provare

Process p = Runtime.getRuntime().exec(new String[]{"csh","-c","cat /home/narek/pk.txt"}); 

invece.

EDIT :: Non ho csh sul mio sistema, quindi ho usato bash invece. Di seguito ha lavorato per me

Process p = Runtime.getRuntime().exec(new String[]{"bash","-c","ls /home/XXX"}); 
+0

non funziona, spiacente – Narek

+0

@Narek. Mi dispiace per quello Ho risolto il problema rimuovendo i \ "extra" Apparentemente non sono necessari Non ho csh sul mio sistema, ma funziona con bash – KitsuneYMG

+3

Come altri hanno già detto questo dovrebbe essere indipendente se hai csh o bash, non è vero? – Narek

26

Usa ProcessBuilder per separare i comandi e gli argomenti al posto degli spazi. Questo dovrebbe funzionare indipendentemente shell utilizzata:

import java.io.BufferedReader; 
import java.io.File; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.util.ArrayList; 
import java.util.List; 

public class Test { 

    public static void main(final String[] args) throws IOException, InterruptedException { 
     //Build command 
     List<String> commands = new ArrayList<String>(); 
     commands.add("/bin/cat"); 
     //Add arguments 
     commands.add("/home/narek/pk.txt"); 
     System.out.println(commands); 

     //Run macro on target 
     ProcessBuilder pb = new ProcessBuilder(commands); 
     pb.directory(new File("/home/narek")); 
     pb.redirectErrorStream(true); 
     Process process = pb.start(); 

     //Read output 
     StringBuilder out = new StringBuilder(); 
     BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream())); 
     String line = null, previous = null; 
     while ((line = br.readLine()) != null) 
      if (!line.equals(previous)) { 
       previous = line; 
       out.append(line).append('\n'); 
       System.out.println(line); 
      } 

     //Check result 
     if (process.waitFor() == 0) { 
      System.out.println("Success!"); 
      System.exit(0); 
     } 

     //Abnormal termination: Log command parameters and output and throw ExecutionException 
     System.err.println(commands); 
     System.err.println(out.toString()); 
     System.exit(1); 
    } 
} 
+0

Anche dopo java.util. *; è correttamente importato Non riesco ad ottenere sopra l'esempio per l'esecuzione. – nottinhill

+0

Che cosa non funziona per te? – Tim

+0

@Stephan Ho aggiornato il codice di esempio sopra per rimuovere le dichiarazioni di registrazione e le variabili che sono state dichiarate al di fuori del codice incollato e che ora dovrebbe essere compilato ed eseguito. Sentiti libero di provare e fammi sapere come funziona. – Tim

10

Sulla @ esempio di Tim per fare un self-contained metodo: (. L'esempio di prova è un command that lists all files in a directory and its subdirectories, recursively, in chronological order)

import java.io.BufferedReader; 
import java.io.File; 
import java.io.InputStreamReader; 
import java.util.ArrayList; 

public class Shell { 

    /** Returns null if it failed for some reason. 
    */ 
    public static ArrayList<String> command(final String cmdline, 
    final String directory) { 
     try { 
      Process process = 
       new ProcessBuilder(new String[] {"bash", "-c", cmdline}) 
        .redirectErrorStream(true) 
        .directory(new File(directory)) 
        .start(); 

      ArrayList<String> output = new ArrayList<String>(); 
      BufferedReader br = new BufferedReader(
       new InputStreamReader(process.getInputStream())); 
      String line = null; 
      while ((line = br.readLine()) != null) 
       output.add(line); 

      //There should really be a timeout here. 
      if (0 != process.waitFor()) 
       return null; 

      return output; 

     } catch (Exception e) { 
      //Warning: doing this is no good in high quality applications. 
      //Instead, present appropriate error messages to the user. 
      //But it's perfectly fine for prototyping. 

      return null; 
     } 
    } 

    public static void main(String[] args) { 
     test("which bash"); 

     test("find . -type f -printf '%[email protected]\\\\t%p\\\\n' " 
      + "| sort -n | cut -f 2- | " 
      + "sed -e 's/ /\\\\\\\\ /g' | xargs ls -halt"); 

    } 

    static void test(String cmdline) { 
     ArrayList<String> output = command(cmdline, "."); 
     if (null == output) 
      System.out.println("\n\n\t\tCOMMAND FAILED: " + cmdline); 
     else 
      for (String line : output) 
       System.out.println(line); 

    } 
} 

A in questo modo, se qualcuno può dirmi perché ho bisogno di quattro e otto barre inverse, invece di due e quattro, posso imparare qualcosa. C'è un altro livello di accadimenti senza scampo rispetto a quello che sto contando.

Modifica: Ho appena provato questo stesso codice su Linux, e qui si scopre che ho bisogno di metà delle backslash nel comando test! (Ovvero: il numero previsto di due e quattro.) Ora non è più solo strano, è un problema di portabilità.

+0

Dovresti porre la tua domanda come nuova domanda StackOverflow, non come parte della tua risposta. – vog

Problemi correlati