我正在尝试(并且失败)找出如何在Java中运行完全交互式shell程序。
以下是该方案:
我有一个跨平台的大型GUI应用程序,用Java编写。我试图添加一个交互式命令行环境来运行无头。事情的一面都很好,花花公子。但是,主GUI的一个功能是编辑文件。现在,对于命令行界面,我希望能够执行外部编辑器来编辑文件,然后返回到我保存和退出后的位置。例如,在Linux上它可以执行" vi / path / to / file"。
那么如何以键盘和显示器与应用程序完全交互的方式执行该命令呢?我不希望它在后台运行。我不希望它通过Java重定向IO,我只想让一个命令在前台运行"#34;直到它存在。
就像我在C中使用system()
功能一样。
到目前为止,我发现的所有内容都在后台运行命令或通过Java管理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();
}
}
}
我希望Runtime.getRuntime()。exec()能够阻止,直到我完成vi
,并且在此期间所有键盘输入将直接进入(RAW
,因为它'已知)直到vi
,所有屏幕输出都会直接返回给用户。
这就是我在C中实现它的方式:
void main() {
system("vi");
}
更新
这实现了预期的结果,但是a)仅限于Linux / OSX(不是那么多问题,但是让它跨平台会很好),并且b)是一个可怕的kludge:
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 :(得分: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();
}
}
}
完成此操作后,您可以在运行时制作实际命令。
答案 1 :(得分:2)
完全等效于system("vi")
:
final ProcessBuilder p = new ProcessBuilder("vi");
p.redirectInput(Redirect.INHERIT);
p.redirectOutput(Redirect.INHERIT);
p.redirectError(Redirect.INHERIT);
p.start().waitFor();
(我知道这是延迟3年,但对于其他有相同问题的人)
答案 2 :(得分:-1)
嗯,首先,ProcessBuilder也在Java 6中。如果你的意思是那个版本不合适,那么我认为你需要知道两条信息。首先,运行“exernal编辑器”的主要方式可能是使用Runtime类和exec方法。我怀疑你已经在做什么了?其次,你当前的GUI,在某种程度上,有一个“事件循环”,这是一个简单但主要的线程,只做“等待事件”(如按键或“窗口事件”),调度该事件感兴趣的听众,然后等待下一个活动。外部编辑器的键盘和事件不会通过这个事件循环来进行......好吧,不管怎样,不使用像OLE API那样更复杂的东西。但是,正是“事件循环”使Java保持活跃和交互,而其他事情也在继续,例如在外部编辑器中进行编辑。我不确定你使用的GUI框架,但是大多数已经有这样的循环,你不必担心它。如果你想在你想要的这个命令行模式下,你不希望你的普通GUI运行,那么你基本上必须复制已经拥有的“事件循环”,并首先启动该线程,然后调用runtime.exec方法。合理?
FWIW,如果您没有“有源”来查看您当前正在使用的GUI框架,如果您想查看一个,只是为了了解有关事件循环的更多信息,Eclipse SWT其中有一个是“显示” “类和一些可能类似于你想要做的例子。 (注意,如果你想知道的话,SWT可以在没有剩下的Eclipse的情况下“独立运行”。
HTH