5

Is there any sane way to run a system command from Java that ignores STDOUT and STDERR? For example, when I try the following:

Process p = Runtime.getRuntime().exec("some_executable_path param1 param2 >NUL 2>&1");

Java tries to parse the command, and ends up escaping the arguments (e.g., prevents the output from being redirected). If I don't redirect STDOUT/STDERR, the buffers fill up and prevent the system call from exiting. The following does what I want, but is extremely cumbersome and creates expensive resources just to throw the output of the system call away:

ProcessBuilder pb = new ProcessBuilder("some_executable_path", "param1", "param2");
pb.redirectErrorStream(true);
final Process p = pb.start();
final Thread redirectToNull = new Thread(() -> {
        final InputStream stdout = process.getInputStream();
        try {
            while (stdout.read() != -1);
        } catch (final Exception e) {
            // Don't care
        }
    }, "Output Consumer Thread");
redirectToNull.setDaemon(true);
redirectToNull.start();

I realize the Java design team is known to be masochistic, but this is ridiculous. I would prefer to deliver a batch or Perl script that wraps the system call with my application rather than use the above code. There has to be an easier way to accomplish this.

So the question is, is there any sane way to run a system command from within Java and ignore the output printed to STDOUT/STDERR?

6
  • 1
    You should at the very least "gobble" them, that is, get the output from the streams, but don't do anything with them, else you may run out of process buffer (I think that is the term for it). Commented Mar 14, 2017 at 23:54
  • 1
    It's one of those problems of "how to please everybody". You could write a small piece of library code which simplifies the code for you to perform the specific task you need, this way you could re-use it as and when needed Commented Mar 14, 2017 at 23:57
  • At the expense of portability you have two options: (1) invoke the shell to run your command, at which point redirection in the command line would work; or (2) specify /dev/null (or whatever it is on your target system) for the redirect destination. Not posting as an answer as I deduce from your example that you're on Windoze, where neither of these hacks may work. Commented Mar 15, 2017 at 1:29
  • @JimGarrison: In Windows the equivalent hacks are ["cmd","/c","command-with-redirections"] and new File("NUL") -- yes the file name NUL is globally reserved; so is CON for the equivalent of /dev/tty and several others. JeffG: it's not that Java 'prevents' redirection, it's that neither Java nor the program you invoke does redirection for < > to start with, only CMD or shell does. Commented Mar 15, 2017 at 1:36
  • @dave_thompson_085 So that should be an answer then. Also, your additional comment to the OP should be in a separate comment so you can \@ping him. Commented Mar 15, 2017 at 1:40

1 Answer 1

9

It's not that Java 'prevents' redirection, it just doesn't affirmatively do it, and neither does your program. When you give CMD a command like program arg1 arg2 >out 2>err <in, it is CMD that sets up those redirections and then invokes program with arg1 arg2 only, not >out etc. On Unix the shells do the same -- there is a choice of several shells, but all of them handle redirection like this. Similarly pipes are set up by CMD or shells, not by either or all of the programs run in those pipes.

Thus on Windows the way to do this is either run CMD and have it do the redirections:

Process p = new ProcessBuilder ("cmd", "/c", "program arg1 arg2 >NUL 2>&1").start();
// this uses CMD's default parsing for args, so they must not contain space
// unless you insert 'data' quotes, or things that look like a substitutable %var% 

or (assuming Java7+) tell ProcessBuilder to do the redirections:

pb.redirectOutput (new File("NUL")).redirectErrorStream(true)
Sign up to request clarification or add additional context in comments.

1 Comment

The second option is what I went with, since it only requires a single dependency on the OS: the name of the null device. This is "NUL" on Windows and "/dev/null" on Linux. I'm surprised such a file is not a public static constant on the File class. Something like File.NullDevice.

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.