lmBuilder.redirectErrorStream();

This is incorrect.

This method only tells whether you redirect stderr to stdout; it does not instruct that stderr should be redirected to it.

What you should use is:

lmBuilder.redirectErrorStream(true);
Answer from fge on Stack Overflow
🌐
Coderanch
coderanch.com › t › 725153 › java › Java-process-builder-returning-correct
Java process builder not returning correct (or any) output (Java in General forum at Coderanch)
January 11, 2020 - Bod McLeon wrote:And the output - well - that's non-existent (there is none - nothing is written to the console). Most likely an exception is being thrown, and you are simply ignoring it. You should at least print the stack. I would also printout the exit value: Edit: updated code ...
🌐
Leo3418
leo3418.github.io › 2021 › 06 › 20 › java-processbuilder-stdout.html
Properly Handling Process Output When Using Java’s ProcessBuilder - Leo3418's Personal Site
Redirect Maven’s output to the Java process’s output with ProcessBuilder.inheritIO, as demonstrated above. Although this could solve the issue, it would significantly alter the behavior of java-ebuilder because originally java-ebuilder would not print Maven’s output to standard output.
🌐
Baeldung
baeldung.com › home › java › core java › guide to java.lang.processbuilder api
Guide to java.lang.ProcessBuilder API | Baeldung
November 26, 2025 - When we want to redirect the process builder’s standard input, output and error destination to a file, we have these three similar redirect methods at our disposal. ... Last but not least, to start a new process with what we’ve configured, we simply call start(). We should note that this class is NOT synchronized. For example, if we have multiple threads accessing a ProcessBuilder instance concurrently then the synchronization must be managed externally.
🌐
Stack Overflow
stackoverflow.com › questions › 39405921 › java-processbuilder-executing-command-has-no-output
Java ProcessBuilder executing command has no output - Stack Overflow
September 9, 2016 - And you are sure that when you run "git clone real-address it works? And that "address" is a real-address when you run the java code? ... The output is likely being written to stderr instead of stdout.
🌐
Stack Overflow
stackoverflow.com › questions › 33841289 › processes-of-processbuilder-are-not-writing-some-output-files-java
Processes of ProcessBuilder are not writing some output files (Java) - Stack Overflow
ProcessBuilder pb = new ProcessBuilder("java", "-jar", jarFile, configFile); Process p = pb.start(); finished = p.waitFor(600, TimeUnit.SECONDS); // print the error output if(finished){ BufferedReader reader = new BufferedReader(new InputStreamReader(p.getErrorStream())); StringBuilder builder = new StringBuilder(); String line = null; while ( (line = reader.readLine()) != null) { builder.append(line); builder.append(System.getProperty("line.separator")); } result = builder.toString(); reader.close(); status = p.exitValue(); } else{ p.destroyForcibly(); result = "Error: maximum time (600 seconds) exceeded."; }
🌐
Stack Overflow
stackoverflow.com › questions › 53269305 › processbuilder-not-outputting-the-correct-output
java - ProcessBuilder not outputting the correct output - Stack Overflow
java · processbuilder · Share ... 1,28822 gold badges1515 silver badges4343 bronze badges 1 · 2 · 1) Perhaps output is printed to stderr, not stdout....
🌐
CloudCompare
cloudcompare.org › cloudcompare website › board index › developers › mac os related topics
Grab command line mode output with Java ProcessBuilder - CloudCompare forum
February 28, 2021 - open -a CloudCompare.app --args -NO_TIMESTAMP -C_EXPORT_FMT LAS -O /Users/s/cc/pcl_1.las -O /Users/s/cc/pcl_2.las -MERGE_CLOUDS It opens the Command Line Mode Window, like the Java approach. An additional "-SILENT" let the app run in the background, (I can see the merged point cloud), but no output to the console.
Find elsewhere
Top answer
1 of 1
1

I just had a similar problem and saw your question while searching for a solution. I could solve it eventually by using a buffered reader, writer, two threads as subclasses and a completable future.

Right after creating the process I create these.

pb = new ProcessBuilder(/*Your command*/);

    try {
        setActiveProcess(pb.start());
    } catch (IOException e) {
        e.printStackTrace();
    }
    
    Thread wait = new Thread(new ProcessWait());
    Thread read = new Thread(new AsyncRead());
    read.start();
    wait.start();

The set activeProcess method simply creates the reader and writer instances as follows

private void setActiveProcess(Process p) {
    if (p == null) {
        activeProcess = null;
        writer = null;
        reader = null;
        readFinished = null;
    }
    else {
        activeProcess = p;
        writer = new BufferedWriter(new OutputStreamWriter(activeProcess.getOutputStream()));
        reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
        readFinished = new CompletableFuture<Boolean>();
    }
}

Then the read thread actively waits for process output

private class AsyncRead implements Runnable {
    @Override
    public void run() {
        int s;
        try {
            while (reader != null && ((s = reader.read()) != -1)) {
                System.out.print((char)s);
            }
            if (readFinished != null) {
                readFinished.complete(true);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

and wait thread actively waits for process to finish without blocking

 private class ProcessWait implements Runnable {
    @Override
    public void run() {
        int status = -1;
        try {
            status = activeProcess.waitFor();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (status != 0) {
            System.err.println("Process failed");
            return;
        }
        try {
            Boolean finished = readFinished.get();
            if (finished) {
                setActiveProcess(null);
                removeFiles();
            }
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        
    }
}

The readFinished variable ensures that the process is not set to null before the reading is not over. I used it for compiling and running C++ programs you can see the whole code in : https://github.com/Onnrr/ProcessBuilderCppCompile

Top answer
1 of 2
2

The problem I see here is that you create a process running a shell (OK), get hold of the input and output streams of that process (OK), read a command from the file (OK) and feed it to the process (OK). Then you keep reading output lines, which succeeds while the the first Java program executes and produces output.

Then the

while ((output = processOutput.readLine()) != null) { ...

blocks as there is neither another line nor EOF.

You can fix this by spawning a thread to read and print processOutput.

Another option (which I'd very much prefer) is to create one process per command. As far as I can see you don't even need a shell: you could execute java SolveProblem ... right away. (Unices have been built for efficient subprocess creation, and don't think the shell does it differently, so there's no additional overhead to be afraid of.)

Just two hints for calling java without a shell: make sure to use the full path name and split the command line into tokens.

Edit And here it is, just using a String[] instead of your text file containing commands.

for( String cmd: new String[]{ "java Y aaa", "java Y bbb","java Y ccc" } ){
     String[] toks = cmd.split( "\\s" );
     ProcessBuilder builder = new ProcessBuilder( toks );
     Process p = builder.start();

     // get output from the process
     InputStream is = p.getInputStream();
     InputStreamReader isr = new InputStreamReader(is);
     BufferedReader processOutput = new BufferedReader(isr);

     InputStream errorStream = p.getErrorStream();
     InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
     BufferedReader processErrorOutput = new BufferedReader(inputStreamReader);
     System.out.println("Executing " + cmd);
     String output;
     while( processErrorOutput.ready() &&
        (output = processErrorOutput.readLine()) != null) {
     System.out.println(output);
     }
     while ((output = processOutput.readLine()) != null) {
     System.out.println(output);
     }
     processErrorOutput.close();
     processOutput.close();
}

Output (silly Y prints argument three times):

Executing java Y aaa
1aaa
2aaa
3aaa
Executing java Y bbb
1bbb
2bbb
3bbb
Executing java Y ccc
1ccc
2ccc
3ccc

Another Edit If a marker line is inserted into the process output and the read loop checks the lines for this marker, the program can be used as it is (except for some corrections for closing processInput):

processInput.write(command + "; echo xxxEOFxxx");
//...
while ((output = processOutput.readLine()) != null
       && ! "xxxEOFxxx".equals(output)) {
    System.out.println(output);
}

Although I dislike the use of "magic strings" in this way it may be permissible here as you know the set of output lines of program Solve.

2 of 2
0

And yet better is to run error and stream reading in separate threads in order to provide make program able to do something else, terminate process for instance

🌐
Oracle
docs.oracle.com › en › java › javase › 11 › docs › api › java.base › java › lang › ProcessBuilder.html
ProcessBuilder (Java SE 11 & JDK 11 )
January 20, 2026 - If set to true, the error stream is written to the same stream as standard output. If starting any of the processes throws an Exception, all processes are forcibly destroyed. The startPipeline method performs the same checks on each ProcessBuilder as does the start() method.
🌐
ZetCode
zetcode.com › java › processbuilder
Java ProcessBuilder - creating processes in Java
May 1, 2025 - The program executes the Windows Notepad application. It returns its exit code. The following example executes a command and shows its output. ... import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; void main() throws IOException { var processBuilder = new ProcessBuilder(); processBuilder.command("cal", "2022", "-m 2"); var process = processBuilder.start(); try (var reader = new BufferedReader( new InputStreamReader(process.getInputStream()))) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } }
Top answer
1 of 1
1

The error message says that Java does not find an executable called zip in the current directory or on the path, which can be seen with:

String systemPath = System.getenv("PATH");
System.out.println("PATH="+systemPath);

Fix your launcher to include the full path to "zip" or fix the PATH used for your Java VM to include a directory that contains zip.

myListOfString.add("/the/path/to/zip");

or something like this (depending on your shell / terminal)

export PATH=/the/path/to:$PATH

As @Abra suggests, there are better ways to ZIP inside Java without relying on ProcessBuilder such as:

public static void zip(Path dir, Path zip) throws IOException
{
    Map<String, String> env = Map.of("create", "true");
    try (FileSystem fs = FileSystems.newFileSystem(zip, env))
    {
        // This predicate processed the action because it makes use of BasicFileAttributes
        // Rather than process a forEach stream which has to call Files.isDirectory(path)
        BiPredicate<Path, BasicFileAttributes> foreach = (p,a) -> {
            copy(p,a, fs.getPath("/"+dir.relativize(p)));
            return false;
        };

        Files.find(dir, Integer.MAX_VALUE, foreach).count();
    }
    System.out.println("ZIPPED "+dir +" to "+zip);
}
private static void copy(Path from, BasicFileAttributes a, Path target)
{
    System.out.println("Copy "+(a.isDirectory() ? "DIR " : "FILE")+" => "+target);
    try
    {
        if (a.isDirectory())
            Files.createDirectories(target);
        else if (a.isRegularFile())
            Files.copy(from, target, StandardCopyOption.REPLACE_EXISTING);
    }
    catch (IOException e)
    {
        throw new UncheckedIOException(e);
    }
}
🌐
Oracle
docs.oracle.com › javase › 8 › docs › api › java › lang › ProcessBuilder.html
ProcessBuilder (Java Platform SE 8 )
April 21, 2026 - Subsequent modifications to this process builder will not affect the returned Process. ... the standard input to the subprocess was redirected from a file and the security manager's checkRead method denies read access to the file, or · the standard output or standard error of the subprocess was redirected to a file and the security manager's checkWrite method denies write access to the file ... Java™ Platform Standard Ed.
Top answer
1 of 2
2

I have never used gksudo, but I googled it and it says it's a GUI version of sudo. I'm guessing that you just launched a GUI app which does not write anything to stdout and which does not return. If so, then the code is doing what I would expect. It is blocking until the process writes a line of text that it can read - which never occurs so it blocks indefinitely.

First test your ProcessBuilder code using a trivial command like "echo" to make sure your Java code is working as expected. Then work your way back. Try running your program as root so you don't need the sudo argument and see if that works. Then finally try to run it using sudo instead of gksudo.

2 of 2
0

I think @user is on the right track, but there are a couple of other possible explanations.

  1. The gksudo command could be asking for a password. I'm not sure where it would ask, but there's a good chance that it won't be the "stdout" stream of the "gksudo" process.

  2. If "gksudo" or the command that you are "gksudo"-ing fails to launch, there is a good chance that it will write an error message to its "stderr" stream. But you are not reading "stderr".

To help diagnose this, you need to try the following:

  • Look in the log file that for "sudo" - it is "/var/log/secure" on my box.
  • Use "ps -efl" (or similar) to see what processes exist while your application is blocked waiting for output. (If that is happening ...)
  • Look to see if "gksudo" is prompting for a password in an unexpected place.
  • Try temporarily tweaking the "sudoers" file to allow the "arpspoof" command to be "sudo"-ed without a password.