не удалось выполнить скрипт из Java-программы?


У меня есть Rscript в строковой переменной, и я хочу выполнить его из программы Java и передать ему некоторую переменную. Если я выполняю этот R-скрипт автономно, он отлично работает. Я преобразовал этот скрипт R в одну строку, экранировав его все с помощью программы Python, как показано ниже:

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

Я использую распечатанную строку и сохраняю ее в строковой переменной, а затем я выполняю с нижеприведенным кодом, и он вообще не работает. Я передаю path и client_users переменную выше R скрипт.

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

    // this is your script in a string
    // String script = "#!/bin/bashnnecho "Hello World"nn readonly PARAM1=$param1n echo $PARAM1nnreadonly PARAM2=$param2n echo $PARAM2nn";
    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 script? Я буду использовать тот же код для bash script и 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

Обновление:-

Вместо того, чтобы использовать мой приведенный выше скрипт, я решил использовать простой скрипт print hell в r, чтобы посмотреть, смогу ли я выполнить его через Ява или нет.

// this will print hello
String script = "#!/usr/bin/env RscriptnsayHello <- function(){n   print('hello')n}nnsayHello()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
1 5

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

...