My experience using Java to do CLI Scripting

Remi Forax forax at univ-mlv.fr
Mon Apr 14 20:48:40 UTC 2025


----- Original Message -----
> From: "Ron Pressler" <ron.pressler at oracle.com>
> To: "cay horstmann" <cay.horstmann at gmail.com>
> Cc: "core-libs-dev" <core-libs-dev at openjdk.org>, "David Alayachew" <davidalayachew at gmail.com>
> Sent: Monday, April 14, 2025 10:30:40 PM
> Subject: Re: My experience using Java to do CLI Scripting

> (moved from amber-dev)
> 
> Hi.
> 
> This does what you want (and could even be combined to a single expression):
> 
>    Process p = new ProcessBuilder("ls", "-al").start();
>    String result = p.inputReader().lines().collect(Collectors.joining("\n"));
> 
> and it’s even nicer in the cases where you may want to process the output line
> by line, as many scripts do.

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);
    }
  }


> 
> — Ron
> 

regards,
Rémi

> 
> 
>> On 14 Apr 2025, at 20:06, Cay Horstmann <cay.horstmann at gmail.com> wrote:
>> 
>> Absolutely, ProcessBuilder/Process is the right approach.
>> 
>> I realize that all those bells and whistles in the Process API are there for a
>> reason, but the API is a bit clunky for the happy day path that one usually has
>> in a script: running a process until it terminates and getting its output. It
>> is trivial to write a couple of helper methods, but it might be nice if the
>> Process API could help out. Something like
>> 
>> Process p = Process.waitFor("ls", "-al");
>> String result = p.output();
>> 
>> Cheers,
>> 
>> Cay
>> 
>> PS. This isn't pretty in Python either:
>> https://docs.python.org/3/library/subprocess.html#subprocess.run
>> 
>> 
>> Il 12/04/25 17:02, Ron Pressler ha scritto:
>>> Hi.
>>> Let’s focus on ProcessBuilder and Process (as I think that’s where you want to
>>> focus, and why I think this discussion is more appropriate for core-libs-dev).
>>> Can you try to show more concretely what the pain point is in your actual code?
>>> The ProcessBuilder example is long because it does multiple things, each of
>>> which may or may not be relevant to your use case. That doing five different
>>> things requires five lines of code doesn’t help us see where your specific pain
>>> point is.
>>> — Ron
>>>> On 12 Apr 2025, at 15:39, David Alayachew <davidalayachew at gmail.com> wrote:
>>>> 
>>>> Hello Amber Dev Team and Kulla Dev Team,
>>>> 
>>>> (I made a reddit post too, if you prefer to interact there instead --
>>>> https://www.reddit.com/r/java/comments/1jx87ys/)
>>>> The following JEP's have released recently.
>>>>     • JEP 495: Simple Source Files and Instance Main Methods
>>>>     • JEP 330: Launch Single-File Source-Code Programs
>>>>     • JEP 222: jshell: The Java Shell (Read-Eval-Print Loop)
>>>> These have made it really easy for me to do CLI scripting in Java, as opposed to
>>>> Bash. However, I've run into some pain points, as I've relied more and more on
>>>> Java.
>>>> For starters, the hand off from Java --> Bash is kind of ugly. Bash --> Java is
>>>> not bad, due to void main(final String[] args), as well as Bash's xargs. But
>>>> Java --> Bash is ugly, and here is an example demonstrating how/why.
>>>> I use AWS CLI to manage my dev environment. It's super powerful, and is all
>>>> available directly from the CLI, using simple Bash or even CMD.
>>>> Let's say I use AWS CLI to gather some ad-hoc information about my entire dev
>>>> environment. How do I manage the multiple handoffs back and forth between AWS
>>>> CLI and Java?
>>>> There are no good answers.
>>>>     • Store the results into a file, then use JShell/java(c) to process the output
>>>>     file from Bash/AWS CLI.
>>>>         • There's multiple handoffs back and forth between AWS CLI and Java. So, every
>>>>         handoff from Java ---> AWS CLI means generating a new file, thus increasing the
>>>>         complexity and cruft. It's unideal.
>>>>     • Use Java's ProcessBuilder and Process classes.
>>>>         • This works, but is heavy-handed. Look at the examples in those links. That is
>>>>         multiple lines of code to represent a single bash command. It does appear to be
>>>>         the idiomatic way, though.
>>>>     • Do all upstream processing with AWS CLI in Bash directly, then do only a
>>>>     single handoff to Java, once I have done all I need to with AWS CLI.
>>>>         • This is definitely the least painful, but it also means I don't use much Java
>>>>         at all. And any changes in upstream processing must be done in Bash to avoid
>>>>         handoff headaches from AWS CLI ---> Java.
>>>>     • Download the AWS SDK Jar files and just do it all in Java.
>>>>         • Ignoring the fact that some things are much harder to do via the AWS Java
>>>>         SDK's, there's actually some functionality that just isn't available via the
>>>>         Java ones. I'd have to recreate it myself, and it would be a significant lift.
>>>> Option 4 is best when I am building an application, but for ad-hoc checks that I
>>>> want to do on the fly (my most common use-case by far), I have been using
>>>> Option 3.
>>>> I just wish I could use more Java. It's a FAR BETTERtool than Bash, but I can't
>>>> justify the level of effort for ad-hoc use cases because of the poor hand off
>>>> from Java --> Bash. And since AWS CLI is only available via Bash/CMD, I'm stuck
>>>> with a bunch of not-good choices.
>>>> CLI Scripting in Java is great, but I wanted to highlight this pain point to
>>>> spread awareness.
>>>> Can you relate?
>>>> 
>> 
>> --
>> 
>> Cay S. Horstmann | https://horstmann.com


More information about the core-libs-dev mailing list