[External] : Re: My experience using Java to do CLI Scripting

Ron Pressler ron.pressler at oracle.com
Tue Apr 15 10:04:32 UTC 2025



> On 15 Apr 2025, at 07:52, Cay Horstmann <cay.horstmann at gmail.com> wrote:
> 
> 
> 
> Il 14/04/25 23:46, Ron Pressler ha scritto:
>>> On 14 Apr 2025, at 21:48, Remi Forax <forax at univ-mlv.fr> wrote:
>>> 
>>> 
>>> Hi Ron,
>>> i think you need to close the inputReader
>>> 
>>>  public static String output(String... args) {
>>>    ProcessBuilder processBuilder = new ProcessBuilder(args);
>>>    try {
>>>      Process process = processBuilder.start();
>>>      try (BufferedReader reader = process.inputReader()) {
>>>        return reader.lines().collect(Collectors.joining("\n"));
>>>      }
>>>    } catch (IOException e) {
>>>      throw new IOError(e);
>>>    }
>>>  }
>> When the process terminates, the InputStream underlying the pipe is closed (after being drained and the unread bytes served by a ByteArrayInputStream), which *I think* should be sufficient, but I could be wrong.
>> — Ron
> 
> Reading the process output into a string or string stream raises a number of worries.
> 
> * Do I need to wait for the process to complete?

I don’t know all the error conditions, but since you’re reading the stream until its end, and this pipe ends when the process closes, then I don’t think you need to also wait for the process complete, but you may want to call waitFor to get the exit status.

> * Do I need to close anything?

It seems to me that all the pipes are closed when the process ends, so no, but I’m not an expert in this area. 

> * How exactly do I use getInputStream()/inputReader() with *extreme care*, as the API doc warns me?

I think that note cautions that if you want to use that pair of methods *together*, then be careful because they’re both reading from the same underlying stream.

> 
> If it is safe to call
> 
>  builder.start().inputReader().lines()
> 
> or
> 
>  builder.start().getInputStream().readAllBytes()
> 
> without waiting or closing, then the API doc could say so.

I think so, and so I guess the doc should say that, but there could be error conditions that complicate matters (e.g. what happens if your thread is interrupted?)

> If not, then maybe a safe method to get the entire output would be appropriate for Process?
> 

In what form, though? A Stream<String> of lines seems the most flexible and convenient — calling .toList() on it seems especially convenient.

But perhaps that hypothetical Process.inputLines() method could also have the returned Stream<String> throw an exception if the process terminates with a non-zero code, making things even more convenient, like so:

    var p = new ProcessBuilder("ls", "-al").start();
    try {
        var lines = p.inputLines().toList();
        ...
    } catch (ProcessFailedException ex) {
        var errorLines = p.errorLines().toList();
        ...
    }

— Ron




More information about the core-libs-dev mailing list