问题描述
我正在尝试使用 Runtime exec 函数从我的 java 后端启动 Rserve。我通常可以执行像 killall 这样的 linux 命令来停止该进程,但我无法启动它。 您可以使用此命令从命令行启动 Rserve
R CMD Rserve
并且工作正常。但是来自java:
Process pr = Runtime.getRuntime().exec("R CMD Rserve")
它不起作用。那么我如何从 java 使用这个命令?
解决方法
exec
与“当我在 shell 中键入它时它起作用”不同。毕竟,当您在“命令行”上键入它时,“命令行”本身就是一个应用程序。通常是 /bin/bash
,但有很多很多壳。
shell 不只是接收您输入的内容,然后将其逐字逐字地扔到操作系统上然后“在这里”。运行这个'。它需要您输入的内容并对其进行按摩。对其应用转换。 然后,经过按摩的东西被扔到操作系统上,并带有“here,run this”。
Java 与此类似,因为它接受您编写的内容,对其进行处理,然后将其扔给操作系统。
这些按摩完全不同。
例如,/bin/bash 会将 *.txt
变成运行 ls *.txt
的结果。 Java 不会这样做,因此如果您尝试运行,例如exec("/bin/ls *.txt")
在 Java 中,它不起作用。 ls 尝试查找字面上称为 *.txt
的文件,并报告找不到它。
诀窍是要了解 bash 对您的输入所做的许多事情,并且不要依赖这些。 java实际上为按摩所做的事情取决于操作系统,所以也不要依赖它。因此,一些规则:
-
始终使用绝对路径。不要运行
R CMD Rserve
。例如,运行/usr/local/share/R/bin/R CMD RServe
。我不知道R
在哪里,但它是您系统上某处的可执行文件。找到绝对路径; bash 所做的按摩之一是应用$PATH
。 Java 可能会或可能不会应用路径,谁知道您的路径设置是什么,以及 java 进程是否与您的 bash 具有相同的 PATH 设置;它可能不会,因此,绝对不要依赖它,并且始终,始终,编写绝对路径。 -
注意 bash 内部结构,切勿使用它们。
ls
和ps
通常是内部结构;根据定义,java 不能运行它们。如果您必须依赖 bashisms,则必须实际运行 bash。不是exec("ls")
,而是exec("/bin/bash","-c","ls")
。 永远不要依赖java的空格分割能力。永远不要使用
exec(cmd)
,也永远不要使用Runtime.getRuntime().exec
。考虑这些被禁止的方法。创建一个ProcessBuilder
,并且始终是List<String>
变体(其中列表中的第一个条目是命令的绝对路径,其余的是命令行参数。 >
这让您:
// to stop
List<String> args = List.of("/bin/bash","killall -9 RServe");
ProcessBuilder pb = new ProcessBuilder(args);
// if you need to read what bash produces,config that here.
pb.start();
// to start
List<String> args = List.of("/abs/path/to/R","CMD","RServe");
ProcessBuilder pb = new ProcessBuilder(args);
// if you need to read what bash produces,config that here.
pb.start();
当然,除非您的java进程是启动它的进程,否则您将无法kill -9
,因此很可能无法从java执行此操作-您只是没有权限。
我知道它改变了我试图调用这个过程的方式。 rzwitserloot 的回答对于解决这个问题非常有用。 我不知道“R CMD”命令的内部结构,但它不喜欢 java 进程构建器。 还有其他方法可以在 R 控制台中调用 Rserver 守护程序,所以我尝试这样做。这工作正常:
List<String> args = List.of("/bin/sh","echo 'library(Rserve);Rserve(args=\"--no-save --slave\");'| /usr/lib/R/bin/R --no-save --slave");
ProcessBuilder pb = new ProcessBuilder(args);
Process p = pb.start();
,
我查看了一些文档并找到了一些东西。试试这个:
try {
String command ="R CMD Rserve";
BufferedWriter out = new BufferedWriter(new FileWriter(new File("path/to/file"),true));
final Process process = Runtime.getRuntime().exec(command);
BufferedReader buf = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = buf.readLine()) != null) {
out.write(line);
out.newLine();
}
buf.close();
out.close();
int returnCode = process.waitFor();
System.out.println("Return code = " + returnCode);
} catch (Exception e) {
e.printStackTrace();
}
让我知道这是否有帮助:)