简体   繁体   English

无法从java程序执行R脚本?

[英]not able to execute R script from java program?

I have a Rscript in a String variable and I want to execute it from Java program and pass some variable to it. 我在String变量中有一个Rscript,我想从Java程序执行它并将一些变量传递给它。 If I execute that R script standalone, it works fine. 如果我独立执行该R脚本,它可以正常工作。 I have converted that R script to one line by escaping it everything by using Python program as shown below: 我通过使用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

I use the printed string out and store it in String variable and then I am executing with below code and it doesn't work at all. 我使用打印出来的字符串并将其存储在String变量中,然后我执行下面的代码,它根本不起作用。 I am passing path and client_users variable to above R script. 我将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);
}

Above code works fine with bash shell script. 上面的代码适用于bash shell脚本。 Is there anything I need to do special for R script? 我需要为R脚本做些什么特别的事吗? I will be using same code for bash script and R scripts as well. 我将对bash脚本和R脚本使用相同的代码。

And this is the error I am getting: 这是我得到的错误:

/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')' 

And if I remove commandList.add("/bin/bash"); 如果我删除commandList.add("/bin/bash"); and add commandList.add("/bin/Rscript"); 并添加commandList.add("/bin/Rscript"); then I see below error: 然后我看到下面的错误:

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

Update:- 更新: -

Instead of using my above script, I decided to use simple print hell script in r to see whether I can execute it through Java or not. 我没有使用上面的脚本,而是决定在r中使用简单的打印地狱脚本来查看是否可以通过Java执行它。

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

When I execute this script with commandList.add("/bin/bash"); 当我用commandList.add("/bin/bash");执行此脚本时commandList.add("/bin/bash"); , I get this error: ,我收到此错误:

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

But if I execute with this commandList.add("/bin/sh"); 但是如果我用这个commandList.add("/bin/sh"); , I get this error: ,我收到此错误:

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

You will have to run /usr/bin/Rscript directly. 您必须直接运行/usr/bin/Rscript Also, this program doesn't read scripts from the standard input (you have to specify the path to the script as an argument for Rscript ), so you will have to: 此外,此程序不读取标准输入中的脚本(您必须指定脚本的路径作为Rscript的参数),因此您必须:

  • Create a temp file 创建临时文件
  • Write your script 写你的脚本
  • Execute your script with Rscript 使用Rscript执行脚本
  • Delete your temp file (as a good programming practice) 删除你的临时文件(作为一个很好的编程实践)

As an example, this is a POC: 例如,这是一个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);
}

As an alternative, and if your script has a "shebang" as the first line , you could do these changes: 作为替代方案, 如果您的脚本有第一行“shebang” ,您可以执行以下更改:

  • set its executable attribute to "true" 将其可执行属性设置为“true”
  • use the path to the temp file as first element in the commandList (ie delete commandList.add("/usr/bin/Rscript"); ) 使用临时文件的路径作为commandList中的第一个元素(即删除commandList.add("/usr/bin/Rscript");

the part of the code to be modified would be: 要修改的代码部分是:

...

// 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);

...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM