【问题标题】:not able to execute R script from java program?无法从 Java 程序执行 R 脚本?
【发布时间】:2015-09-16 20:26:08
【问题描述】:

我在 String 变量中有一个 Rscript,我想从 Java 程序中执行它并将一些变量传递给它。如果我独立执行该 R 脚本,它工作正常。我已通过使用 Python 程序将所有内容转义,将 R 脚本转换为一行,如下所示:

import json

jsonstr = json.dumps({"script": """\
#!/usr/bin/Rscript

# read the data file
library('jsonlite')
library('rpart')

args <- as.list(Sys.getenv(c(
                        "path",
                        "client_users")))

if (args[["path"]]==""){
    args[["path"]] <- "."
}

# other stuff here
# other stuff here

"""})

print jsonstr

我使用打印出来的字符串并将其存储在 String 变量中,然后我使用下面的代码执行它,它根本不起作用。我将pathclient_users 变量传递给上面的R 脚本。

public static void main(String[] args) throws IOException, InterruptedException {

    // this is your script in a string
    // String script = "#!/bin/bash\n\necho \"Hello World\"\n\n readonly PARAM1=$param1\n echo $PARAM1\n\nreadonly PARAM2=$param2\n echo $PARAM2\n\n";
    String script = "above R Script here";

    List<String> commandList = new ArrayList<>();
    commandList.add("/bin/bash");

    ProcessBuilder builder = new ProcessBuilder(commandList);
    builder.environment().put("path", "/home/david");
    builder.environment().put("client_users", "1000");
    builder.redirectErrorStream(true);
    Process shell = builder.start();

    // Send your script to the input of the shell, something
    // like doing cat script.sh | bash in the terminal
    try(OutputStream commands = shell.getOutputStream()) {
        commands.write(script.getBytes());
    }

    // read the outcome
    try(BufferedReader reader = new BufferedReader(new InputStreamReader(shell.getInputStream()))) {
        String line;
        while((line = reader.readLine()) != null) {
            System.out.println(line);
        }
    }

    // check the exit code
    int exitCode = shell.waitFor();
    System.out.println("EXIT CODE: " + exitCode);
}

以上代码在 bash shell 脚本中运行良好。我需要为 R 脚本做些什么特别的事情吗?我也会对 bash 脚本和 R 脚本使用相同的代码。

这是我得到的错误:

/bin/bash: line 7: -: No such file or directory /bin/bash: line 10: syntax error near unexpected token `'jsonlite'' /bin/bash: line 10: `library('jsonlite')' 

如果我删除 commandList.add("/bin/bash"); 并添加 commandList.add("/bin/Rscript"); 然后我会看到以下错误:

Cannot run program "/bin/Rscript": error=2, No such file or directory

更新:-

我决定不使用上面的脚本,而是在 r 中使用简单的 print hell 脚本,看看我是否可以通过 Java 执行它。

// this will print hello
String script = "#!/usr/bin/env Rscript\nsayHello <- function(){\n   print('hello')\n}\n\nsayHello()\n";

当我使用commandList.add("/bin/bash"); 执行此脚本时,我收到此错误:

/bin/bash: line 2: syntax error near unexpected token `('
/bin/bash: line 2: `sayHello <- function(){'

但是如果我用这个commandList.add("/bin/sh"); 执行,我会得到这个错误:

/bin/sh: 2: Syntax error: "(" unexpected

【问题讨论】:

    标签: java r bash runtime processbuilder


    【解决方案1】:

    您必须直接运行/usr/bin/Rscript。此外,该程序不会从标准输入读取脚本(您必须将脚本的路径指定为Rscript 的参数),因此您必须:

    • 创建临时文件
    • 编写脚本
    • 使用 Rscript 执行脚本
    • 删除您的临时文件(作为一种良好的编程习惯)

    例如,这是一个 POC:

    public static void main(String[] args) throws IOException, InterruptedException {
    
        // Your script
        String script = "#!/usr/bin/env Rscript\n" +
                "\n" +
                "sayHello <- function() {\n" +
                "    print('hello')\n" +
                "}\n" +
                "\n" +
                "sayHello()\n";
    
        // create a temp file and write your script to it
        File tempScript = File.createTempFile("test_r_scripts_", "");
        try(OutputStream output = new FileOutputStream(tempScript)) {
            output.write(script.getBytes());
        }
    
        // build the process object and start it
        List<String> commandList = new ArrayList<>();
        commandList.add("/usr/bin/Rscript");
        commandList.add(tempScript.getAbsolutePath());
        ProcessBuilder builder = new ProcessBuilder(commandList);
        builder.redirectErrorStream(true);
        Process shell = builder.start();
    
        // read the output and show it
        try(BufferedReader reader = new BufferedReader(
                new InputStreamReader(shell.getInputStream()))) {
            String line;
            while((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        }
    
        // wait for the process to finish
        int exitCode = shell.waitFor();
    
        // delete your temp file
        tempScript.delete();
    
        // check the exit code (exit code = 0 usually means "executed ok")
        System.out.println("EXIT CODE: " + exitCode);
    }
    

    作为替代方案,如果您的脚本有一个“shebang”作为第一行,您可以进行以下更改:

    • 将其可执行属性设置为“true”
    • 使用临时文件的路径作为命令列表中的第一个元素(即删除commandList.add("/usr/bin/Rscript");

    要修改的代码部分是:

    ...
    
    // create a temp file and write your script to it
    File tempScript = File.createTempFile("test_r_scripts_", "");
    tempScript.setExecutable(true);
    try(OutputStream output = new FileOutputStream(tempScript)) {
        output.write(script.getBytes());
    }
    
    // build the process object and start it
    List<String> commandList = new ArrayList<>();
    commandList.add(tempScript.getAbsolutePath());
    ProcessBuilder builder = new ProcessBuilder(commandList);
    
    ...
    

    【讨论】:

      最近更新 更多