2012-03-13 13 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はI型の文字を読み込みません。

だから.../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に接続されているからです(これは明らかに質問が本当に求めているものです)。 –

3

JavaがRuntime.exec()経由でプログラムを実行するとき(これはcommons-execが最後に行う)、プログラムの入力、出力、およびエラーストリームを入出力ストリームとしてJavaアプリケーションに接続します。そのようなストリームは確かにターミナルではありません。たとえば、テキスト・カーソルを移動させることはできません(文字がないため)、テキストの色を変更したり、Shiftキーが押された場合に検出することはできません物理的なキーボードではありません)。したがって、viのようなインタラクティブなアプリは、端末のような状況下では実際には機能しません。

ところで、あなたが提供するコマンドライン引数がシェルによって解析されるのか、プログラムに直接渡されるのかわかりません。後者の場合、/dev/ttyへのリダイレクトは、たとえJavaが何らかの形でプログラムがJavaの接続ストリームを何か他のものに置き換えることを許可する方法があったとしても機能しませんでした。

なぜなら、Javaプログラムの中からviを実行したいのは少し奇妙なようです。

だから私は、最善の解決策がkonsoleまたはgnome-terminalまたはxtermなどの端末エミュレータを実行し、そのコマンドライン(例えばkonsole -e vi)に対応する引数を渡すことによって、VIを実行させることですね。この場合、端末のウィンドウがポップアップし、viがその内部で機能することができます。もちろん、ヘッドレスサーバーを使用している場合は動作しませんが、viを実行すると便利ではありません。

+0

私は 'System.in'をサブプロセスの' OutputStream'(サブプロセスのstdin)にポンピングするなど、いくつか試してみましたが、基本的には機能しません。悲しい、これは私が本当にやりたいことです。 –

+0

@ChristopherSchultz残念ながら、入力を生成し、出力を消費する必要があります。そうしないと、フルバッファによってプロセスがフリーズすることがあります。 –

+0

はい、すべてのストリームをポンピングする必要があることはわかっています。それでも単純に機能しません。私はJavaからやることをあきらめました。幸いにも、Cから行うのはfork + execのように簡単です。私はJNIのほうが面倒な価値がないので、JNIにそのようなfork + execを実行してもらうよう気にしませんでした。 –

2

しかし、Java 1以降。7あなたは透過的にこれを使用すると、JVMのために1.7以上透過的にVIを開くことができるようになります

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"); 

フルコンソール機能にリダイレクトし、持っている次の例を使用することができます。

関連する問題