2012-03-13 16 views
2

我希望能夠在我的Java程序中啓動VI,並在繼續之前等待用戶退出VI。下面的代碼片段,我目前:如何在commons-exec下從Java內部啓動VI?

...  
String previewFileName="test.txt"; // the file to edit 
CommandLine cmdLine = new CommandLine("/usr/bin/vi"); 
cmdLine.addArgument(previewFileName); 
cmdLine.addArgument(">/dev/tty"); 
cmdLine.addArgument("</dev/tty"); 

Executor executor = new DefaultExecutor(); 
try 
{ 
    DefaultExecuteResultHandler resultHandler = new ResetProcessResultHandler(cmdLine); 
    executor.execute(cmdLine, resultHandler); 
} catch (IOException e) 
{ 
    throw new Error("Cannot execute command: /usr/bin/vi " + previewFileName, e); 
} 
log.info("waiting..."); 
cmdLine.wait(); 
log.info("...done"); 
... 

private class ResetProcessResultHandler extends DefaultExecuteResultHandler 
{ 
    private final CommandLine mCommandLine; 
    public ResetProcessResultHandler(CommandLine pCommandLine) 
    { 
     mCommandLine = pCommandLine; 
    } 
    public void onProcessComplete(int exitValue) 
    { 
     log.info("Command complete rc(" + exitValue + ")"); 
     if (exitValue != 0) 
     { 
      throw new RuntimeException("VI command error [rc=" + exitValue + "] "); 
     } 
     mCommandLine.notify(); 
    } 
    public void onProcessFailed(ExecuteException e) 
    { 
     if (e.getExitValue() != 0) 
     { 
      log.error("launch VI error " + e.toString()); 
      throw new RuntimeException("VI command failed [" + e.getCause() + "] "); 
     } 
     else 
     { 
      log.info("VI complete rc(" + e.getExitValue() + ")"); 
     } 
     mCommandLine.notify(); 
    } 
} 

我收到輸出:

Vim: output is not to a terminal 
Vim: input is not from a terminal 

但後來我看到畫彷彿VI已經開始屏幕;而VI不會讀取我輸入的字符。

所以...從/ dev/tty重定向並沒有這樣做。

有人必須做到這一點 - 幫助!

感謝,

馬克

回答

-1

我不知道如何與公地EXEC做到這一點,

但是標準的Java應該是沿着線的東西...

String[] command = {"/usr/bin/vi", "test.txt"}; 
Process vimProcess = Runtime.getRuntime().exec(command); 
vimProcess.waitFor(); 

這將導致當前線程等待進程完成。您還可以使用 vimProcess.getInputStream(),getOutputStream()和getErrorStream()將它們重定向到日誌文件或任何您想要的位置。

查看此處瞭解更多詳情。 http://docs.oracle.com/javase/6/docs/api/java/lang/Runtime.html

希望這會有所幫助。

+0

這是行不通的,因爲vi沒有被帶到前臺並附加到用戶的tty(這顯然是問題的真正要求)。 – 2013-06-27 20:57:37

3

當Java通過Runtime.exec()(這是commons-exec最終做的)運行程序時,它將程序的輸入,輸出和錯誤流作爲輸入/輸出流連接到Java應用程序。這樣的流肯定不是終端,例如你不能移動文本光標(因爲它沒有),改變文本顏色,或者檢測是否按下了鍵(因爲它只是一個字節流而不是物理keyborad)。因此,像vi這樣的交互式應用在終端等條件下無法真正起作用。

順便說一下,我不確定命令行參數是否由shell解析或直接傳遞給程序。在後一種情況下,即使有某種方式讓Java以某種方式允許程序用其他內容替換Java的連接流,您的重定向到/dev/tty也不可能工作。

順便說一句,爲什麼你想從Java程序中運行vi似乎有點奇怪。

所以我想的最佳解決方案是執行終端仿真器等konsolegnome-terminalxterm,讓它通過使對應的參數其命令行(例如konsole -e vi)上運行VI。在這種情況下,終端的窗口應該彈出並且vi可以在其內部起作用。當然,如果你在一個無頭服務器上,它不會工作,但是運行vi無論如何都是無用的。

+0

我已經嘗試了一些東西,例如將'System.in'泵到子進程的'OutputStream'(這是子進程的stdin)等等,基本上它不起作用。傷心,因爲這是我真正想做的事情。 – 2013-06-27 21:11:41

+0

@ChristopherSchultz不幸的是,你需要產生輸入和消耗輸出 - 否則該進程可能會由於完全緩衝而凍結。 – 2013-06-28 19:09:49

+0

是的,我知道你必須抽取所有的流。它依然根本不起作用。我已經放棄了從Java做起。幸運的是,從C執行它就像fork + exec一樣簡單。我沒有打算試圖編寫JNI去做這樣的fork + exec來讓它工作,因爲大多數JNI不值得這樣麻煩。 – 2013-07-16 21:49:17

2

但是自從Java 1。7,您可以使用下面的例子中透明地重定向並有充分的控制檯功能

System.out.println("STARTING VI"); 
ProcessBuilder processBuilder = new ProcessBuilder("/usr/bin/vi"); 
processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT); 
processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT); 
processBuilder.redirectInput(ProcessBuilder.Redirect.INHERIT); 

Process p = processBuilder.start(); 
    // wait for termination. 
    p.waitFor(); 
System.out.println("Exiting VI"); 

這將允許你透明地打開VI的JVM 1.7+。