1

I want to be able to execute an external command from java, eg "ls", and get the output, both output and error streams, as a string, and in realtime, and in the order they were generated.

So, if the output from the command is something like:

blah     <- to stdout
foo      <- to stderr
bar      <- to stdout

Then, ideally I want the output string, and the realtime output, to look like:

blah
foo
bar

Naive methods produce either:

blah
bar

(ie no stderr output)

or:

blah
bar
foo

(ie the order is rearranged so that the stdout and stderr messages are not interlaced with each other).

1

3 Answers 3

3

Use ProcessBuilder and set redirectErrorStream(true).

Sign up to request clarification or add additional context in comments.

Comments

3

This isn't always possible.

If you use the ProcessBuilder API, you can merge the stdout and stderr streams into one (using redirectErrorStream(true)), so you can read both outputs in a single InputStream. But that means you can't tell from which stream the data originally came from.

If you read stdout and stderr as two streams, you will need NIO or two Java threads. In both cases, processing one output will block the other (or rather, the other stream won't be processed timely). That will lead to swapped lines.

If the child process doesn't flush the output and you use pipes, then this gets worse because stdout will be sent to your process in 4KB blocks while stderr will usually arrive line-by-line.

There is no platform-independent workaround, I'm afraid. If you only need a solution which works on Unix, you can use Pseudo TTYs (man 4 pty) to simulate a shell but these are hard to set up from Java since you need to call OS functions.

One approach might be to use Perl or similar to run your command in a PTY (this causes stdout to become line buffered), read stdout and stderr from there and prefix each line with 1 for stdout and 2 for stderr.

Comments

1

I would suggest you to use Apache commons exec API as they are more sophisticated API to use.

See DefaultExecutor: You can :

  • set a current working directory for the subprocess
  • provide a set of environment variables passed to the subprocess
  • capture the subprocess output of stdout and stderr using an ExecuteStreamHandler
  • kill long-running processes using an ExecuteWatchdog
  • define a set of expected exit values
  • terminate any started processes when the main process is terminating using a ProcessDestroyer

1 Comment

It seems really complicated to use, and not obviously documented. Does it do anything that I can't do with a ProcessBuilder?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.