Friends of OpenJDK Today

Java Tips # 01 –  Writing Shebang Scripts in Pure Java

October 29, 2024

Author(s)

  • Avatar photo
    A N M Bazlur Rahman

    A N M Bazlur Rahman is a Software Engineer with over a decade of specialized experience in Java and related technologies. His expertise has been formally recognized through the prestigious ... Learn more

Did you know you can write a CLI script in Java just as easily as you would in a bash script, and run it directly from the shell?

This is commonly called a shebang script, though we are mostly familiar with writing them in bash. Bash scripts are great, but they can be obscure to developers who aren’t familiar with the syntax. As a Java developer, you'd likely prefer to get things done the Java way. Well, since Java 11, you can do exactly that!

I'll assume Java is already installed on your machine. To confirm, open your terminal and run:

java --version

You should see something like this:

java --version
java 21.0.1 2023-10-17 LTS
Java(TM) SE Runtime Environment (build 21.0.1+12-LTS-29)
Java HotSpot(TM) 64-Bit Server VM (build 21.0.1+12-LTS-29, mixed mode, sharing)

If you don’t see a similar output, it means Java isn’t installed. Sorry to make you uncomfortable, but you'll need to install it now! The easiest way is through SDKMan.

In one of my previous articles, I explained how to build CLI applications with PicoCLI. If you're interested, feel free to check that out. But in this article, we'll keep it simple, using plain Java with no external libraries.

Getting Started

First, create a new file called hello.java:

touch hello.java

Then, paste the following code into the file:

#!/usr/bin/java --source 21

import java.time.LocalDate;
import java.util.Random;
import java.util.Scanner;

public class HelloCLI {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Random random = new Random();
        System.out.println("Welcome to the Java CLI. Type 'help' for a list of commands or 'exit' to quit.");

        while (true) {
            System.out.print("Command> ");
            String command = scanner.nextLine().trim().toLowerCase();

            switch (command) {
                case "greet" -> System.out.println("Hello, Java enthusiast!");
                case "date" -> System.out.println("Today's date: " + LocalDate.now());
                case "time" -> System.out.println("Current time: " + java.time.LocalTime.now());
                case "random" -> System.out.println("Random number (1-100): " + (random.nextInt(100) + 1));
                case "add" -> {
                    System.out.print("Enter first number: ");
                    double num1 = scanner.nextDouble();
                    System.out.print("Enter second number: ");
                    double num2 = scanner.nextDouble();
                    scanner.nextLine(); // Consume the newline
                    System.out.println("Result: " + (num1 + num2));
                }
                case "multiply" -> {
                    System.out.print("Enter first number: ");
                    double num1 = scanner.nextDouble();
                    System.out.print("Enter second number: ");
                    double num2 = scanner.nextDouble();
                    scanner.nextLine(); // Consume the newline
                    System.out.println("Result: " + (num1 * num2));
                }
                case "help" -> {
                    System.out.println("""
                        Available commands:
                        - greet: Prints a friendly greeting.
                        - date: Displays today's date.
                        - time: Displays the current time.
                        - random: Generates a random number between 1 and 100.
                        - add: Adds two numbers.
                        - multiply: Multiplies two numbers.
                        - help: Shows this help message.
                        - exit: Exits the program.
                        """);
                }
                case "exit" -> {
                    System.out.println("Exiting... Goodbye!");
                    return; // Terminate the program
                }
                default -> System.out.println("Unknown command: " + command + ". Type 'help' for a list of commands.");
            }
        }
    }
}

Key Point: Shebang Line

Notice the first line: #!/usr/bin/java --source 21. This is the crucial part of the file, instructing the shell to use Java to run the script in source form using Java 21.

You can remove the .java extension if you want; that’s also fine. Just keep the file named hello. To rename the file, use the following command:

mv hello.java hello

Make It Executable

Now, to make this script executable, run the following command:

chmod +x ./hello

That's it! You can now run it with:

./hello

Here’s what you should see when you run it:

./hello
Welcome to the Java CLI. Type 'help' for a list of commands or 'exit' to quit.
Command> help
Available commands:
- greet: Prints a friendly greeting.
- date: Displays today's date.
- time: Displays the current time.
- random: Generates a random number between 1 and 100.
- add: Adds two numbers.
- multiply: Multiplies two numbers.
- help: Shows this help message.
- exit: Exits the program.

Command> greet
Hello, Java enthusiast!
Command> date
Today's date: 2024-10-27
Command> random
Random number (1-100): 99
Command> add
Enter first number: 5
Enter second number: 39999
Result: 40004.0
Command> exit
Exiting... Goodbye!

Bonus Tip: Running From Anywhere

If you'd like to run this script from anywhere on your machine, simply move the file to the /usr/local/bin/ folder:

sudo mv ./hello /usr/local/bin/

Now, you can invoke it from any directory just by typing hello in your terminal.

Learn About How Your Peers Use Java (and win a Macbook Air or Apple AirPods Max)

Take a short State of Java Survey by Azul by 6:30pm CT on November 8, 2024. Optionally, enter the prize draw and receive the survey results to learn about Java developers and about their OpenJDK versions, distributions, frameworks, libraries, Cloud costs, and application performance.

Get Started

Topics:

Related Articles

View All

Author(s)

  • Avatar photo
    A N M Bazlur Rahman

    A N M Bazlur Rahman is a Software Engineer with over a decade of specialized experience in Java and related technologies. His expertise has been formally recognized through the prestigious ... Learn more

Comments (4)

Your email address will not be published. Required fields are marked *

Highlight your code snippets using [code lang="language name"] shortcode. Just insert your code between opening and closing tag: [code lang="java"] code [/code]. Or specify another language.

Save my name, email, and website in this browser for the next time I comment.

Java Weekly, Issue 566 | Baeldung

[…] Java Tips # 01 – Writing Shebang Scripts in Pure Java […]

Erik Weibust

Howdy Bazlur,

I appreciated you blog post. I have not attempted any scripting with Java. When I run the example you shared above I get some errors related to the shebang. I’ve also shared that the path should work for me.

Any idea?


~/bin via ☕ v21.0.4
❯ ./hello.java
./hello.java:1: error: illegal character: '#'
#!/usr/bin/java --source 21
^
./hello.java:1: error: class, interface, enum, or record expected
#!/usr/bin/java --source 21
^
./hello.java:4: error: class, interface, enum, or record expected
import java.util.Random;
^
./hello.java:5: error: class, interface, enum, or record expected
import java.util.Scanner;
^
4 errors
error: compilation failed

~/bin via ☕ v21.0.4
❯ which -a java
/Users/erikweibust/.sdkman/candidates/java/current/bin/java
/usr/bin/java

Avatar photo
A N M Bazlur Rahman

This worked on my machine without any issues. Could it be possible that there’s a copy-paste error? Where did you try it on?

I’ve pasted this on GitHub Gist. Please try copying it from here and let me know what you see:

https://gist.github.com/rokon12/16eb3d96b3afc4a23d4aeb1299318f48

Erik Weibust

The only way I could get this to work was removing the .java extension for the file. I thought it was ok with or without the .java but that is not the case for me.

Subscribe to foojay updates:

https://foojay.io/feed/
Copied to the clipboard