2012-03-13 3 views
2

Я хотел бы иметь возможность запускать VI из моей программы Java и дождаться, когда пользователь покинет VI перед продолжением. Вот фрагмент кода, который я в настоящее время:Как я могу запустить VI из Java под commons-exec?

...  
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 пользователя (что, очевидно, действительно задает вопрос). –

3

Когда Java запускает программу через Runtime.exec() (и это то, что делает commons-exec в конце), она подключает входные, выходные и потоковые потоки программы к вашему Java-приложению в качестве потоков ввода-вывода. Такой поток, конечно, не является терминалом, вы не можете, например, перемещать в нем текстовый курсор (поскольку он его не имеет), изменять цвета текста или определять, нажата ли клавиша Shift (так как это всего лишь поток байтов а не физический keyborad). Таким образом, интерактивное приложение вроде vi не может функционировать в таких условиях, как в терминале.

Кстати, я не уверен, что аргументы командной строки, которые вы поставляете, обрабатываются оболочкой или передаются непосредственно программе. В последнем случае ваше перенаправление на /dev/tty не могло работать, даже если бы был способ Java, чтобы каким-то образом позволить программе заменять связанные потоки Java с чем-то другим.

Как в стороне, кажется немного странным, почему вы хотели бы запустить vi изнутри программы Java.

Так что я думаю, что лучшим решением будет выполнять эмулятор терминала, как konsole или gnome-terminal или xterm и дайте ему VI, передавая соответствующий аргумент в его командной строке (например, konsole -e vi). В этом случае окно терминала должно появиться и в нем может функционировать vi. Конечно, это не сработает, если вы находитесь на безголовом сервере, но тогда запуск vi не может быть полезен в любом случае.

+0

Я пробовал несколько вещей, таких как перекачка 'System.in' в' OutputStream' подпроцесса (который является stdin подпроцесса) и т. Д., И в основном он не работает. Грустно, поскольку это то, что я действительно хотел бы сделать. –

+0

@ChristopherSchultz К сожалению, вам нужно как производить вход, так и потреблять - в противном случае процесс может замерзнуть из-за полного буфера. –

+0

Да, я знаю, что вам нужно перекачивать все потоки. Он по-прежнему просто не работает. Я отказался от этого с Java. К счастью, делать это с C так же просто, как fork + exec. Я не потрудился попытаться написать JNI, чтобы сделать такой fork + exec, чтобы заставить его работать, потому что в основном JNI не стоит хлопот. –

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 прозрачно для виртуальной машины Java 1.7+.

Смежные вопросы