Проблема с использованием Apache Commons exec
Я пытаюсь использовать Apache Commons для запуска сценария, и сценарий запуска из терминала выглядит выводит данные, подобные следующим:
РЕДАКТИРОВАТЬ - отредактировано, чтобы ввести waitFor как предложено.
$./old-regress.sh
End with '*' as postcode !
postcode: city: street: house number: country: name: PDC:
postcode :
city :
street :
house_num :
routing_code :
post_freight_centre:
ic_c_err_code : 0260
post_code_err_code : ----
city_error_code : g---
street_error_code : ---f
local_gov_number 1 :
local_gov_number 2 :
State :
admin. district :
district :
local gov. unit :
routing_code :
error_text_address :
./old-regress.sh: line 2: 9722 Segmentation fault ./ictest < /tmp/tmp_inp_file
Отказ сегментации ожидается, поскольку это - то, как двоичный файл ictest
(сторонний) работает.
Теперь, когда я пытаюсь выполнить тот же скрипт через мое приложение, используя Apache Commons exec, кажется, что он печатает только ошибку, а не вывод. Мой фрагмент кода, который пытается запустить скрипт, выглядит следующим образом:
public class Test {
public String execToString(String command) throws Exception {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
CommandLine commandline = CommandLine.parse(command);
DefaultExecutor exec = new DefaultExecutor();
exec.setWorkingDirectory(new File("/home/vigna"));
PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream);
exec.setStreamHandler(streamHandler);
exec.setExitValue(139);
DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();
exec.execute(commandline,resultHandler);
resultHandler.waitFor();
return(outputStream.toString());
}
public static void main(String[] argv) throws Exception {
Test test = new Test();
System.out.println(test.execToString("./old-regress.sh"));
}
Вывод, который возвращает приведенный выше фрагмент, выглядит следующим образом:
./old-regress.sh: line 2: 15981 Segmentation fault ./ictest < /tmp/tmp_inp_file
РЕДАКТИРОВАТЬ 2 - я пытался использовать ProcessBuilder. ниже мой код -
public class PBTest
{
public static void main(String[] args) throws Exception
{
ProcessBuilder pb = new ProcessBuilder("./old-regress.sh");
pb.directory(new File("/home/xxx/"));
Process p = pb.start();
String output = loadStream(p.getInputStream());
String error = loadStream(p.getErrorStream());
int rc = p.waitFor();
System.out.println("Process ended with rc=" + rc);
System.out.println("\nStandard Output:\n");
System.out.println(output);
System.out.println("\nStandard Error:\n");
System.out.println(error);
}
private static String loadStream(InputStream s) throws Exception
{
BufferedReader br = new BufferedReader(new InputStreamReader(s));
StringBuilder sb = new StringBuilder();
String line;
while((line=br.readLine()) != null)
sb.append(line).append("\n");
return sb.toString();
}
}
Результат использования ProcessBuilder следующий:
Process ended with rc=139
Standard Output:
Standard Error:
./old-regress.sh: line 2: 3975 Segmentation fault ./ictest < /tmp/tmp_inp_file
Я думаю, что 139 из-за ошибки сегментации и может вызывать ее сбой. Есть предложения?
Любой указатель на то, что я делаю здесь не так? Как мне также захватить вывод?
2 ответа
Я рекомендую использовать org.apache.commons.exec.LogOutputStream
вместо ByteArrayOutputStream. Конструктор PumpStreamHandler с одним аргументом захватывает stdout и stderr - так что у вас все хорошо. Создайте свой экземпляр LogOutputStream и передайте его в качестве единственного аргумента PumpStreamHandler (как будто вы BAOS).
Поскольку вы просто вызываете waitFor() в обработчике, просто используйте метод синхронного выполнения в DefaultExecutor: int exitValue = exec.execute(commandline)
,
Я бы попытался установить код выхода на ноль, а затем сам проверить выходное значение из ответа от execute. Я ожидаю, что проблема в том, что ваш ByteArrayOutputStream усекается из Исключения, перебивая стандартный вывод, не полностью сбрасывая содержимое.
You are doing.
exec.execute(commandline);
// gives the program no time to start or run.
return(outputStream.toString());
Вместо этого вы должны сделать что-то вроде
exec.execute(commandline).waitFor();
// get the output only after the program has finished.
return(outputStream.toString());