在Java中运行交互式Shell程序

Maj*_*nko 8 java exec

我正在尝试(但失败)弄清楚如何在Java中运行完全交互式的shell程序。

这是场景:

我有一个跨平台并用Java编写的大型GUI应用程序。为此,我试图添加一个交互式的命令行环境以无头运行。这方面的一切都很好,花花公子。但是,主GUI的功能之一是编辑文件。现在,对于命令行界面,我希望能够执行外部编辑器来编辑文件,然后返回保存和退出后的状态。例如,在Linux上,它可以执行“ vi / path / to / file”。

那么,如何以键盘和显示器与应用程序完全交互的方式执行该命令?我不希望它在后台运行。我不希望它通过Java重定向IO,我只希望一个命令“在前台”运行直到存在。

就像我system()在C中使用该函数一样。

到目前为止,我发现的所有内容都在后台运行命令或通过Java通过IO传递IO,这不适用于交互式(非行模式)应用程序。

哦,还有最后一个警告:我仅限于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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我希望Runtime.getRuntime()。exec()一直阻塞到我完成操作为止vi,在此期间,所有键盘输入都将直接进入(RAW众所周知),vi并且所有屏幕输出都将直接返回,而不会受到影响。用户。

这就是我要在C中实现的方式:

void main() {
    system("vi");
}
Run Code Online (Sandbox Code Playgroud)

更新:

这样可以达到预期的结果,但是a)仅限于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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Maa*_*oAk 5

精确等效项system("vi")是:

final ProcessBuilder p = new ProcessBuilder("vi");
p.redirectInput(Redirect.INHERIT);
p.redirectOutput(Redirect.INHERIT);
p.redirectError(Redirect.INHERIT);

p.start().waitFor();
Run Code Online (Sandbox Code Playgroud)

(我知道这有3年的延迟,但对于其他有相同问题的人)

  • 您还可以用单个 `p.inheritIO()` 调用替换三个 `redirect*` 调用。另请注意,这些方法仅在 JDK 1.7+ 中可用。 (2认同)

小智 -1

首先,ProcessBuilder 也在 Java 6 中。如果您的意思是该版本不充分或其他什么,那么我认为您需要了解两条信息。首先,运行“外部编辑器”的主要方法可能是使用 Runtime 类和 exec 方法。我怀疑这就是你已经在做的事情?其次,您当前的 GUI 在某种程度上有一个“事件循环”,它是一个简单但主要的线程,除了“等待事件”(例如按键或“窗口事件”)之外什么也不做,调度该事件发送给感兴趣的听众,然后等待下一个事件。外部编辑器的按键和事件不会通过此事件循环……好吧,无论如何,如果不使用更复杂的东西(例如 OLE API),这并不容易。但是,正是“事件循环”使 Java 保持活力和交互性,同时其他事情也继续进行,例如在外部编辑器中进行编辑。我不确定您使用的是什么 GUI 框架,但大多数框架已经有这样的循环,您不必担心它。如果您说在您想要的命令行模式下,您不希望正常的 GUI 运行,那么您基本上必须复制具有的“事件循环”,并首先启动该线程,然后调用runtime.exec方法。合理?

FWIW,如果您没有“源代码”来查看当前正在使用的 GUI 框架,如果您想查看一个框架,只是为了了解有关事件循环的更多信息,Eclipse SWT在“显示”类中有一个以及一些示例可能与您想要做的类似。(请注意,SWT 可以“独立”运行,无需 Eclipse 的其余部分,以防您想知道)。

华泰