简体   繁体   中英

Trouble using Apache Commons exec


Im trying to use Apache commons to run a script and the script from run from a terminal looks outputs data similar to the following --

$./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

The segmentation fault is expected as that is how the binary ictest (third-party) works.

Now when i try executing the same script through my app using Apache Commons exec, it only seems to be printing the error and not the output. My code snippet that tries to run the script is as follows --

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

The output that the above snippet returns is as follows --

./old-regress.sh: line 2: 15981 Segmentation fault      ./ictest < /tmp/tmp_inp_file

-- -

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

the result of using ProcessBuilder is as follows --

Process ended with rc=139
Standard Output:


Standard Error:

./old-regress.sh: line 2:  3975 Segmentation fault      ./ictest < /tmp/tmp_inp_file

Im thinking 139 is because of the segmentation fault and may be causing it to fail. Any suggestons ?

Any pointer on what im doing wrong here ? How do i capture the output as well ?

I recommend using org.apache.commons.exec.LogOutputStream instead of ByteArrayOutputStream. The single argument PumpStreamHandler constructor captures stdout and stderr -- so you are good there. Create your instance of LogOutputStream, and pass it as the single argument to PumpStreamHandler (like you are the BAOS).

Since you are just calling waitFor() on the Handler, just use the synchronous execute method on the DefaultExecutor: int exitValue = exec.execute(commandline) .

I would try setting exit code to null, then check exitValue yourself from the response from execute. I expect the problem is that your ByteArrayOutputStream is getting truncated from the Exception, beating the stdout, not fully flushing the content.

You are doing.

exec.execute(commandline);
// gives the program no time to start or run.
return(outputStream.toString());

You should instead do something like

exec.execute(commandline).waitFor();    
// get the output only after the program has finished.
return(outputStream.toString());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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