2009-09-11 3 views
80

Я пытаюсь выполнить некоторые команды Linux из Java, используя redirection (> &) и pipe (|). Как Java может вызывать команды csh или bash?Хотите вызвать команду linux shell из Java

Я пытался использовать это:

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

Но это не совместимо с переадресаций или труб.

+2

'cat' и' csh' не имеют ничего общего друг с другом. – Bombe

+4

Я могу понять вопрос для других команд, но для кота: почему, черт возьми, вы просто не читаете в файле? – Atmocreations

+7

Каждый первый раз ошибается - Java exec() не использует оболочку базовой системы для выполнения команды (как указывает kts). Перенаправление и конвейер - это функции реальной оболочки и недоступны с помощью exec() Java. – SteveD

ответ

76

Exec не выполняет команду в вашей оболочке

попробовать

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

вместо этого.

EDIT :: У меня нет csh в моей системе, поэтому вместо этого я использовал bash. Для меня работало

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

не работает, извините – Narek

+0

@Narek. Извини за это. Я исправил его, удалив лишние файлы. По-видимому, они не нужны. У меня нет csh в моей системе, но он работает с bash. – KitsuneYMG

+3

Как уже упоминалось, это должно быть независимым, у вас есть csh или bash, не так ли? – Narek

26

Используйте ProcessBuilder для разделения команд и аргументов вместо пробелов. Это должно работать независимо от оболочки, используемой:

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

Даже после java.util. *; правильно импортирован, я не могу получить выше пример для запуска. – nottinhill

+0

Что не работает для вас? – Tim

+0

@Stephan Я обновил приведенный выше код примера, чтобы удалить операторы ведения журнала и переменные, которые были объявлены вне вставленного кода, и теперь он должен компилироваться и запускаться. Не стесняйтесь попробовать и сообщить мне, как это работает. – Tim

10

Основываясь на @ примере Тима сделать автономный метод: (. Тест пример является 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); 

    } 
} 

К Кстати, если кто-нибудь может сказать мне, почему мне нужны четыре и восемь обратных косых черт, вместо двух и четырех я могу чему-то научиться. Существует еще один уровень неудачи, чем то, что я считаю.

Редактировать: Просто попробовал этот же код в Linux, и там выяснилось, что мне нужна половина так же, как и обратная косая черта в тестовой команде! (То есть: ожидаемое число два и четыре.) Теперь это уже не просто странно, это проблема переносимости.

+0

Вы должны задать свой вопрос как новый вопрос StackOverflow, а не как часть своего ответа. – vog

Смежные вопросы