Проблема с использованием 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());
Другие вопросы по тегам