用命令参数启动本地terminal(Java)

我有一个看似微不足道的问题:我想从一个java进程启动一个terminal,给terminal一个或两个命令。 我有一个简单的示例代码,可以在Windows上使用CMD完美地工作。 但是我还没有能够在Linux和Mac OS上实现同样的行为。 我知道,该命令需要改变,但不幸的是,我一直无法将一串parameter passing给Mac上的terminal。

这里是Windows的工作代码:

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上,我已经能够使用这个命令创build一个terminal:

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

但是,这只能在terminal调用,但不能与java进程一起使用。

TLDR :这个命令的Linux和Mac相当于什么:

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

Solutions Collecting From Web of "用命令参数启动本地terminal(Java)"

我建议你使用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个操作系统。 这三个布尔值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终端命令(使用运行时?)如果有任何事情,他们有几个方法在终端中运行脚本。