1. 程式人生 > 程式設計 >如何使用JAVA呼叫SHELL

如何使用JAVA呼叫SHELL

通過ProcessBuilder進行排程

這種方法比較直觀,而且引數的設定也比較方便, 比如我在實踐中的程式碼(我隱藏了部分業務程式碼):

ProcessBuilder pb = new ProcessBuilder("./" + RUNNING_SHELL_FILE,param1,param2,param3);
    pb.directory(new File(SHELL_FILE_DIR));
    int runningStatus = 0;
    String s = null;
    try {
      Process p = pb.start();
      try {
        runningStatus = p.waitFor();
      } catch (InterruptedException e) {
      }
 
    } catch (IOException e) {
    }
    if (runningStatus != 0) {
    }
    return;

這裡有必要解釋一下幾個引數:

RUNNING_SHELL_FILE:要執行的指令碼
SHELL_FILE_DIR:要執行的指令碼所在的目錄; 當然你也可以把要執行的指令碼寫成全路徑。
runningStatus:執行狀態,0標識正常。 詳細可以看java文件。
param1,param3:可以在RUNNING_SHELL_FILE指令碼中直接通過1,2,$3分別拿到的引數。

直接通過系統Runtime執行shell

這個方法比較暴力,也比較常用, 程式碼如下:

p = Runtime.getRuntime().exec(SHELL_FILE_DIR + RUNNING_SHELL_FILE + " "+param1+" "+param2+" "+param3);
p.waitFor();

我們發現,通過Runtime的方式並沒有builder那麼方便,特別是引數方面,必須自己加空格分開,因為exec會把整個字串作為shell執行。

可能存在的問題以及解決方法

如果你覺得通過上面就能滿足你的需求,那麼可能是要碰壁了。你會遇到以下情況。

沒許可權執行

這個情況我們團隊的朱東方就遇到了, 在做DTS遷移的過程中,要執行包裡面的shell指令碼, 解壓出來了之後,發現執行不了。 那麼就按照上面的方法授權吧

ProcessBuilder builder = new ProcessBuilder("/bin/chmod","755",tempFile.getPath());
      Process process = builder.start();
      int rc = process.waitFor();

java進行一直等待shell返回

這個問題估計更加經常遇到。 原因是, shell指令碼中有echo或者print輸出, 導致緩衝區被用完了! 為了避免這種情況, 一定要把緩衝區讀一下, 好處就是,可以對shell的具體執行狀態進行log出來。 比如上面我的例子中我會變成:

ProcessBuilder pb = new ProcessBuilder("./" + RUNNING_SHELL_FILE,keyword.trim(),taskId.toString(),fileName);
    pb.directory(new File(CASPERJS_FILE_DIR));
    int runningStatus = 0;
    String s = null;
    try {
      Process p = pb.start();
      BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
      BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
      while ((s = stdInput.readLine()) != null) {
        LOG.error(s);
      }
      while ((s = stdError.readLine()) != null) {
        LOG.error(s);
      }
      try {
        runningStatus = p.waitFor();
      } catch (InterruptedException e) {
      }

記得在start()之後, waitFor()之前把緩衝區讀出來打log, 就可以看到你的shell為什麼會沒有按照預期執行。 這個還有一個好處是,可以讀shell裡面輸出的結果, 方便java程式碼進一步操作。