使用命令参数启动本机终端 (Java)



我有一个看似微不足道的问题:我想从java进程启动终端,并给终端一两个命令。 我有一个简单的示例代码,可以在带有CMD的窗口中完美运行。但是我无法在Linux或Mac OS机器上实现相同的确切行为。 我知道,命令需要更改,但不幸的是,我无法将一串参数传递给 Mac 上的终端。

这里是窗口的工作代码:

import java.lang.ProcessBuilder.Redirect;
public class ExecTest {
public static void main(String[] args){ 
String cmd = "cmd /c start cmd.exe /K "echo hello && echo bye"";
try {
Process p = Runtime.getRuntime().exec(cmd);
p.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
}
}

在 lubuntu 上,我已经能够使用以下命令创建一个终端:

lxterminal -l -e 'echo hello && echo bye && read'

但这仅在由终端调用时才有效,而不适用于 java 进程。

.

TLDR:这个命令的 Linux 和 Mac 等效物是什么:

cmd /c start cmd.exe /K "echo hello && echo bye"

我建议您使用ProcessBuilder来受益于更轻松的输出重定向和在不使用线程的情况下使用它的能力,并且还将命令作为String[]而不是平面String传递,以便能够支持各种包装方法。如果你更喜欢坚持Runtime.exec(),它也支持String[],但下面的示例使用ProcessBuilder

static int executeInTerminal(String command) throws IOException, InterruptedException {
final String[] wrappedCommand;
if (isWindows) {
wrappedCommand = new String[]{ "cmd", "/c", "start", "/wait", "cmd.exe", "/K", command };
}
else if (isLinux) {
wrappedCommand = new String[]{ "xterm", "-e", "bash", "-c", command};
}
else if (isMac) {
wrappedCommand = new String[]{"osascript",
"-e", "tell application "Terminal" to activate",
"-e", "tell application "Terminal" to do script "" + command + ";exit""};
}
else {
throw new RuntimeException("Unsupported OS ☹");
}
Process process = new ProcessBuilder(wrappedCommand)
.redirectErrorStream(true)
.start();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line); // Your superior logging approach here
}
}
return process.waitFor();
}

在 3 个操作系统上测试。这里无法解释 3 个布尔值is{Windows|Linux|Mac},因为操作系统检测是另一个主题,因此对于示例,我保持简单并处理了该方法。

ProcessBuilder配置为将 stderr 重定向到 stdout,以便需要读取单个流。然后读取并记录该流,因为您必须使用 stderr 和 stdout,以防终端本身打印内容(不是您在终端中运行的命令,这是关于终端本身打印的内容),如果它打印太多,您可能会让进程无限期阻塞,等待缓冲区被读取。看到这个不错的答案。

对于macOS,如果您传递的命令始终是单个可执行脚本,您也可以使用{"open", "-a", "Terminal", command},但这不适用于echo hello && echo bye。同样,您可以使用{"/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal", command},这将使您运行应用程序的第二个实例,但具有相同的限制。

最后说明:你可以提供一个合理的基本实现,但你可能需要让它可配置,以允许替代终端应用程序(特别是在Linux上,它变化很大)。

String[] cmd = {"echo", "hello", "&&", "echo", "hi"};Runtime.getRuntime().exec(cmd);

有多种方法可以做到这一点,但这应该适合您。Mac 上的可执行文件应在终端中自动运行。

可能类似于: 如何从 Java 运行 Mac OS 终端命令(使用运行时? 如果有的话,他们有几种在终端中运行脚本的方法。

最新更新