2014-11-09 2 views
7

У меня есть следующий класс. Это позволяет мне выполнять команды через java.Java - Run Bash Commands

public class ExecuteShellCommand { 

public String executeCommand(String command) { 

    StringBuffer output = new StringBuffer(); 

    Process p; 
    try { 
     p = Runtime.getRuntime().exec(command); 
     p.waitFor(); 
     BufferedReader reader = 
         new BufferedReader(new InputStreamReader(p.getInputStream())); 

     String line = "";   
     while ((line = reader.readLine())!= null) { 
      output.append(line + "\n"); 
     } 

    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

    return output.toString(); 

} 

} 

Когда я запускаю команды, результат предыдущей команды не сохраняется. Например:

public static void main(String args[]) { 

    ExecuteShellCommand com = new ExecuteShellCommand(); 
    System.out.println(com.executeCommand("ls")); 
    System.out.println(com.executeCommand("cd bin")); 
    System.out.println(com.executeCommand("ls")); 

} 

дает выход:

bin 
src 


bin 
src 

Почему вторая команда «LS» не показать содержимое каталога «бин»?

+0

Смотрите также [Когда Runtime.exec() не будет] (http://www.javaworld.com/article/2071275/core-java/when-runtime-exec---won-t. html) для многих хороших советов по правильному созданию и обработке процесса.Затем проигнорируйте это, ссылаясь на 'exec' и используйте' ProcessBuilder' для создания процесса. –

+0

Здравствуйте. Я попытался использовать ваш класс для выполнения Bash-Commands в моем приложении Java, но когда я запускаю команду «cat», он возвращает null ... – Zanidd

ответ

2

Каждый вызов выполняется в его собственной оболочке. Таким образом, «cd» второго вызова не рассматривается третьим.

См. https://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html#exec(java.lang.String).

Указывает, что команда запускается в отдельном процессе. Таким образом, вы создали 3 процесса.

Если вы хотите, чтобы все 3 в том же процессе, попробуйте следующее:

com.executeCommand("ls; cd bin; ls"); 
+0

Есть ли способ выполнить ряд команд в том же контексте? – mickzer

+0

Я обновил свой ответ с этой информацией. – EJK

+0

Позвольте мне перефразировать мой вопрос .. Есть ли способ выполнить ряд команд в одном и том же контексте один за другим? Например, можно ли взять серию пользовательских входов и передать их в процесс оболочки? – mickzer

2

каждую команду вы работаете имеет свою собственную Баш оболочку, так что, как только вы компакт-диск в этот каталог и для следующей команды вы открываете новым Баш оболочки

попробуйте изменить команду

ls bin 
+0

Есть ли способ выполнить ряд команд в том же контексте? – mickzer

+0

Вы можете обернуть их в скрипт bash и вызвать его, а также использовать 'ProcessBuilder' вместо' Runtime' –

+0

Незначительная коррекция, как написано в вопросе, команды выполняются без оболочки. Указанные программы просто выполняются в раздвоенном процессе. – Dev

1

Каждая команда выполняется индивидуально. Они не разделяют контекст.

+0

Есть ли способ выполнить ряд команд в том же контексте? – mickzer

9

Вы начинаете новый процесс с Runtime.exec(command), и каждый процесс, который вы запускаете, имеет собственный рабочий каталог. Обычно это каталог, в котором был запущен процесс, но вы можете изменить каталог, в котором вы запускаете процесс.

Я бы рекомендовал использовать ProcessBuilder

ProcessBuilder pb = new ProcessBuilder("ls"); 
pb.inheritIO(); 
pb.directory(new File("bin")); 
pb.start(); 

Если вы хотите запустить несколько команд в оболочке, было бы лучше, чтобы создать временный скрипт и запустить это.

public void executeCommands() throws IOException { 

    File tempScript = createTempScript(); 

    try { 
     ProcessBuilder pb = new ProcessBuilder("bash", tempScript.toString()); 
     pb.inheritIO(); 
     Process process = pb.start(); 
     process.waitFor(); 
    } finally { 
     tempScript.delete(); 
    } 
} 

public File createTempScript() throws IOException { 
    File tempScript = File.createTempFile("script", null); 

    Writer streamWriter = new OutputStreamWriter(new FileOutputStream(
      tempScript)); 
    PrintWriter printWriter = new PrintWriter(streamWriter); 

    printWriter.println("#!/bin/bash"); 
    printWriter.println("cd bin"); 
    printWriter.println("ls"); 

    printWriter.close(); 

    return tempScript; 
} 

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

+0

В createTempScriptYou() вам необходимо закрыть файл перед его возвратом. – Fabien

+0

@Fabien Вы правы. Я добавил строку, которая закрывает 'PrintWriter'. Как следствие, основные читатели и потоки также будут закрыты. –

+0

Могу ли я выполнить несколько команд без создания временного файла? –

0

для дальнейшего использования: запуск Баш команды после того, как компакт-диск, в подкаталоге:

import java.io.BufferedReader; 
import java.io.InputStreamReader; 

/* 

$ (D=somewhere/else ; mkdir -p $D ; cd $D ; touch file1 file2 ;) 
$ javac BashCdTest.java && java BashCdTest 
.. stdout: -rw-r--r-- 1 ubuntu ubuntu 0 Dec 28 12:47 file1 
.. stdout: -rw-r--r-- 1 ubuntu ubuntu 0 Dec 28 12:47 file2 
.. stderr: /bin/ls: cannot access isnt_there: No such file or directory 
.. exit code:2 

*/ 
class BashCdTest 
    { 
    static void execCommand(String[] commandArr) 
     { 
     String line; 
     try 
      { 
      Process p = Runtime.getRuntime().exec(commandArr); 
      BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(p.getInputStream())); 
      while ((line = stdoutReader.readLine()) != null) { 
       // process procs standard output here 
       System.out.println(" .. stdout: "+line); 
       } 
      BufferedReader stderrReader = new BufferedReader(new InputStreamReader(p.getErrorStream())); 
      while ((line = stderrReader.readLine()) != null) { 
       // process procs standard error here 
       System.err.println(" .. stderr: "+line); 
       } 
      int retValue = p.waitFor(); 
      System.out.println(" .. exit code:"+Integer.toString(retValue)); 
      } 
     catch(Exception e) 
      { System.err.println(e.toString()); } 
     } 

    public static void main(String[] args) 
     { 
     String flist = "file1 file2 isnt_there"; 
     String outputDir = "./somewhere/else"; 
     String[] cmd = { 
      "/bin/bash", "-c", 
      "cd "+outputDir+" && /bin/ls -l "+flist+" && /bin/rm "+flist 
      }; 
     execCommand(cmd); 
     } 
    } 
2

Вы можете сформировать одну сложную команду Баш, которая делает все: «LS; кд бен; Ls». Для выполнения этой работы вам необходимо явно вызвать bash. Этот подход должен дать вам всю мощь командной строки bash (обработка цитат, расширение $, трубы и т. Д.).

/** 
* Execute a bash command. We can handle complex bash commands including 
* multiple executions (; | && ||), quotes, expansions ($), escapes (\), e.g.: 
*  "cd /abc/def; mv ghi 'older ghi '$(whoami)" 
* @param command 
* @return true if bash got started, but your command may have failed. 
*/ 
public static boolean executeBashCommand(String command) { 
    boolean success = false; 
    System.out.println("Executing BASH command:\n " + command); 
    Runtime r = Runtime.getRuntime(); 
    // Use bash -c so we can handle things like multi commands separated by ; and 
    // things like quotes, $, |, and \. My tests show that command comes as 
    // one argument to bash, so we do not need to quote it to make it one thing. 
    // Also, exec may object if it does not have an executable file as the first thing, 
    // so having bash here makes it happy provided bash is installed and in path. 
    String[] commands = {"bash", "-c", command}; 
    try { 
     Process p = r.exec(commands); 

     p.waitFor(); 
     BufferedReader b = new BufferedReader(new InputStreamReader(p.getInputStream())); 
     String line = ""; 

     while ((line = b.readLine()) != null) { 
      System.out.println(line); 
     } 

     b.close(); 
     success = true; 
    } catch (Exception e) { 
     System.err.println("Failed to execute bash with command: " + command); 
     e.printStackTrace(); 
    } 
    return success; 
}