2015-04-19 32 views
3

我正在嘗試(和失敗)來研究如何從Java內部運行完全交互式的shell程序。在Java中運行交互式shell程序

這裏的情景:

我有一個大的GUI應用程序,它是跨平臺和Java編寫的。爲此,我試圖添加一個用於運行無頭的交互式命令行環境。事情的這一面都很好,很棒。但是,主GUI的其中一個功能是編輯文件。現在,對於命令行界面,我希望能夠執行一個外部編輯器來編輯這些文件,然後在我保存並退出後返回到我所在的位置。例如,在Linux上它可以執行「vi/path/to/file」。

那麼,我怎樣才能以鍵盤和顯示器與應用程序完全互動的方式執行該命令呢?我不希望它在後臺運行。我不希望它通過Java重定向IO,我只希望這一個命令在「前臺」運行,直到它存在。

就像,好像我用的system()功能C.

到目前爲止,我發現一切都在後臺運行或管IO通過Java,這將不用於交互式(非行工作命令模式)應用程序。

哦,還有一個最後的警告:我僅限於Java 1.6的兼容性,所以我不能用ProcessBuilder做一些奇特的事情。

這裏的強制性SSCCE:

class exetest { 
    public static void main(String[] args) { 
     try { 
      Process p = Runtime.getRuntime().exec("vi"); 
      p.waitFor(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

我期望調用Runtime.getRuntime()EXEC()阻塞,直到我在vi已經完成,在此期間的所有鍵盤輸入會去直接(RAW因爲它是已知的)到vi,並且所有屏幕輸出將直接返回到用戶的原始狀態。

這是我將如何實現它在C:

void main() { 
    system("vi"); 
} 

更新:

這實現了預期的結果,而是一種)被限制到Linux/OSX(沒有那麼多的一個問題,但會很高興地把它跨平臺),和b)是一個可怕的雜牌組裝電腦:

import java.io.*; 

class exetest { 
    public static void main(String[] args) { 
     try { 
      Process p = Runtime.getRuntime().exec("/bin/bash"); 
      OutputStream stdin = p.getOutputStream(); 
      PrintWriter pw = new PrintWriter(stdin); 
      pw.println("vi </dev/tty> /dev/tty"); 
      pw.close(); 
      p.waitFor(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 
+0

你想要類似https://github.com/ronniedong/Expect-for-Java? –

+0

不,我不知道。我不希望Java與執行的程序進行交互,我希望用戶與它進行交互。所以他們輸入'edit myfile'並執行'vi/path/to/myfile',然後用戶編輯文件,就好像他們在終端輸入了'vi/path/to/myfile'一樣。 – Majenko

回答

-1

嗯,首先,是的ProcessBuilder Java 6中得。如果你的意思是那個版本不夠完善,或者某個東西,那麼我認爲你需要知道兩條信息。首先,運行「exernal編輯器」的主要方式可能是使用Runtime類和exec方法。我懷疑那是你在做什麼?其次,當前的GUI在某個級別上有一個「事件循環」,它是一個簡單但主要的線程,除了「等待事件」(例如按鍵或「窗口事件」)之外什麼都不做,派發該事件感興趣的聽衆,然後等待下一個事件。對外部編輯器的按鍵和事件不會通過這個事件循環來完成......好吧,不管怎樣,不要使用更復雜的東西,比如OLE API。但是,正是「事件循環」使Java保持活躍和交互性,而其他事情也在繼續,例如在外部編輯器中進行編輯。我不確定你使用的是什麼GUI框架,但大多數已經有了這樣一個循環,你不應該擔心它。如果你說在你想要的這種命令行模式下,你不想讓普通的GUI運行,那麼你基本上必須重複已經存在的「事件循環」,並且首先啓動該線程,然後調用runtime.exec方法。合理?

FWIW,如果您沒有「有資源」查看您當前正在使用的GUI框架,如果您想查看其中的一個,僅需瞭解更多關於事件循環的信息,Eclipse SWT就有一個「Display」類,一些可能與您想要做的相似的例子。 (請注意,SWT可以在沒有其他Eclipse的情況下「獨立運行」,以防萬一您想知道)。

HTH

+0

在CLI模式下運行時,不存在GUI。 GUI代碼甚至沒有開始。當它完全擺動時。沒有GUI,沒有GUI事件循環。我實際上使用JLine作爲CLI界面。 – Majenko

+0

6中的ProcessBuilder沒有Redirect類。 – Majenko

3

我事先聲明,這是一個可怕的雜牌組裝電腦,但由於你的約束,我不相信你會找到更優雅。

此外,它不會在Windows上工作。

使用bash:

class Exetest { 
    public static void main(String[] args) { 
     try { 
      // Create a one-liner for bash 
      // Note that the trick is to do all the redirects and 
      // give the name of the file in a single argument. 
      String [] commandline = new String[3]; 
      commandline[0] = "bash"; 
      commandline[1] = "-c"; 
      commandline[2] = "vi </dev/tty >/dev/tty test.txt"; 
      Process p = Runtime.getRuntime().exec(commandline); 
      p.waitFor(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

完成後這種方式,可以在運行時手藝實際的命令。

+0

你是對的,這是一個可怕的kludge;)是的,它達到了預期的結果,但我不確定我能忍受這種實現。編輯器的可執行文件將在運行時決定,而且我不確定是否可以在一行中創建包含重定向的bash命令,因此它必須隨時生成腳本以供執行。不太好。 – Majenko

+0

@Majenko我編輯了一個基於bash的命令,可以在運行時製作命令。 – RealSkeptic

+0

我之前嘗試過 - 重定向不起作用。你必須通過標準輸入發送它,就像我上面編輯的那樣。 – Majenko