我有一个看似微不足道的问题:我想从java进程启动一个终端并给终端一个或两个命令。 我有一个简单的示例代码,可以在带有CMD的窗口上完美运行。但我无法在Linux或Mac OS机器上实现相同的行为。 我知道,该命令需要更改,但遗憾的是我无法将一串参数传递给Mac上的终端。
这里是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上,我已经能够用这个命令创建一个终端:
lxterminal -l -e 'echo hello && echo bye && read'
但是这只有在终端调用时才有效,但在java进程中没有。
。
TLDR :此命令的Linux和Mac等价物是什么:
cmd /c start cmd.exe /K \"echo hello && echo bye\"
答案 0 :(得分:1)
我建议你使用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,以防终端本身打印东西(不是您在终端中运行的命令,这是关于终端本身打印的内容),如果它打印得太多了有可能让进程无限期地阻塞,等待缓冲区被读取。 See this nice answer
对于macOS,如果您传递的命令始终是单个可执行脚本,您也可以使用{"open", "-a", "Terminal", command}
,但这不适用于echo hello && echo bye
。同样地,您可以使用{"/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal", command}
,这会让您运行应用程序的第二个实例,但具有相同的限制。
最后说明:您可以提供合理的基本实现,但您可能需要对其进行配置以允许其他终端应用程序(尤其是在Linux上有很多变化的应用程序)。
答案 1 :(得分:0)
String[] cmd = {"echo", "hello", "&&", "echo", "hi"};
Runtime.getRuntime().exec(cmd);
有多种方法可以做到这一点,但这应该对你有用。 Mac上的可执行文件应在终端中自动运行。
可能类似于:How To Run Mac OS Terminal Commands From Java (Using Runtime?) 如果有什么,他们有一些方法在终端中运行脚本。