не удалось выполнить скрипт из 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 ответ:
Вам придется запустить
/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); ...