Reputation: 1239
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 --
EDIT --Edited to introduce waitFor as suggested.
$./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
EDIT 2 -- i tried using ProcessBuilder. the following is my code --
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 ?
Upvotes: 0
Views: 3557
Reputation: 14691
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.
Upvotes: 1
Reputation: 533442
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());
Upvotes: 0