2009-09-11 18 views
80

Estoy intentando ejecutar algunos comandos Linux desde Java usando la redirección (> &) y pipes (|). ¿Cómo puede Java invocar los comandos csh o bash?Quiere invocar un comando linux shell desde Java

He intentado utilizar esto:

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

pero no es compatible con redirecciones o tuberías.

+2

'cat' y' csh' no tienen nada que ver el uno con el otro. – Bombe

+4

puedo entender la pregunta para otros comandos, pero para gato: ¿por qué demonios no acabas de leer en el archivo? – Atmocreations

+7

Todo el mundo se equivoca esta primera vez: el ejecutor de Java() no usa el shell del sistema subyacente para ejecutar el comando (como señala kts). La redirección y la canalización son características de un shell real y no están disponibles desde el administrador de Java(). – SteveD

Respuesta

76

ejecutivo no ejecuta un comando en la shell

tratar

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

lugar.

EDIT :: No tengo csh en mi sistema, así que usé bash en su lugar. Los siguientes trabajó para mí

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

no funciona, lo siento – Narek

+0

@Narek. Lo siento por eso. Lo arreglé quitando los extra \ "'Aparentemente no son necesarios. No tengo csh en mi sistema, pero funciona con bash. – KitsuneYMG

+3

Como otros han mencionado, esto debería ser independiente de si tienes csh o bash, ¿no es así? – Narek

26

Uso ProcessBuilder para separar los comandos y argumentos en lugar de espacios. Esto debería funcionar independientemente de la shell usada:

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

Incluso después de java.util. *; se importa correctamente No puedo obtener el ejemplo anterior para ejecutar. – nottinhill

+0

¿Qué no funciona para usted? – Tim

+0

@Stephan He actualizado el código de ejemplo anterior para eliminar las declaraciones de registro y las variables que se declararon fuera del código pegado, y ahora debería compilarse y ejecutarse. No dude en probar y hágame saber cómo funciona. – Tim

10

Sobre la base @ ejemplo de Tim para hacer un método de auto-contenido: (. El ejemplo de prueba es 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); 

    } 
} 

Por el De esta forma, si alguien puede decirme por qué necesito cuatro y ocho barras invertidas allí, en lugar de dos y cuatro, puedo aprender algo. Hay un nivel más de desaparición que lo que estoy contando.

Edit: ¡Acabo de probar este mismo código en Linux, y resulta que necesito la mitad de las barras invertidas en el comando de prueba! (Es decir: el número esperado de dos y cuatro). Ahora ya no es simplemente extraño, es un problema de portabilidad.

+0

Debe hacer su pregunta como una nueva pregunta de StackOverflow, no como parte de su respuesta. – vog

Cuestiones relacionadas