Usage

A minimal script is a single .java file with a typical static void main method or a .jsh file which will be passed to jshell.

Below is an (almost) minimal example you can save in helloworld.java or simply run jbang init helloworld.java:

///usr/bin/env jbang "$0" "$@" ; exit $? (1)

class helloworld { (2)

    public static void main(String[] args) {
        if(args.length==0) {
            System.out.println("Hello World!");
        } else {
            System.out.println("Hello " + args[0]);
        }
    }
}
1 By using this // style instead of shebang #! you trick bash, zsh etc. to run this as a script while still being valid java code.
2 A classname, can be anything when using jbang but to be valid java for most IDEs you’ll want to name it the same as the source file.

Now to run this you can call it via jbang:

jbang helloworld.java

or if on Linux/OSX/AIX run it directly. If you created it manually you need to mark it as executable before running it.

chmod +x helloworld.java
./helloworld.java jbang!

If you are using another shell than bash or zsh, like Fish shell be aware that such shell limits the syntax in top line to start with !# thus it won’t be as transparent. Here you will need to run using jbang directly, i.e. jbang helloworld.java jbang!.

When no JDK version is available in the PATH, JDK 11 will be downloaded by default to bootstrap jbang. If your script requires a higher version and you don' want to download two JDK’s, you can define an alternative default with JBANG_DEFAULT_JAVA_VERSION env variable.

$ JBANG_DEFAULT_JAVA_VERSION=14 jbang my-script.java

Note that if JDK is found in the PATH, JBANG_DEFAULT_JAVA_VERSION will be ignored.

It’s also possible to override the exact JDK distribution that will be used by setting the JBANG_JDK_VENDOR env variable. By default this will either be temurin or aoj, but it can also be set to any of the other vendors supported by Foojay, like azul, debian, microsoft, openjdk, oracle or redhat.

$ JBANG_DEFAULT_JAVA_VERSION=18 JBANG_JDK_VENDOR=oracle jbang my-script.java

Note that if a JDK of matching version is already installed these env variables will have no effect! They only take effect when an actual JDK installation is performed. To force JBang to install such a JDK one would first have to uninstall the existing JDK and then reinstall it with these env variables set to their intended values.

Default application

If you pass a directory or a url ending in / jbang will look for main.java to run as default application for that directory / location.

URLs from Trusted Sources

You can use http(s):/ and file:/ url’s for input:.

jbang https://gist.github.com/maxandersen/f43b4c52dfcfc42dcd59a04e49acf6ec

For safety reasons jbang will not run arbitrary urls before you indicated you trust their source. Thus when running the above for the first time you will see the following warning about the url not being a trusted source:

jbang https://gist.github.com/maxandersen/f43b4c52dfcfc42dcd59a04e49acf6ec
[jbang] https://gist.github.com/maxandersen/f43b4c52dfcfc42dcd59a04e49acf6ec is not from a trusted source thus not running it automatically.

If you trust the url to be safe to run you can do one of the following:
0) Trust once: Add no trust, just run this time
1) Trust this url in future:
    jbang trust add https://gist.github.com/maxandersen/


Any other response will result in exit.

[jbang] Type in your choice (0 or 1) and hit enter. Times out after 10 seconds.

You can then choose 0 to run once or 1 to trust the suggested url. If you don’t answer within 10 seconds jbang will exit.

To enable running it without such question you need to mark that url or a sub part of it as a trusted source. i.e. jbang trust add https://github.com/maxandersen/ will tell jbang to trust anything with that base url.

You can see more in the comments of the ~/.jbang/trusted-sources.json.

Sites such as GitHub, gitlab, bitbucket, gist, carbon.now.sh jbang will try and extract the proper source rather than the raw html. i.e. doing jbang https://carbon.now.sh/ae51bf967c98f31a13cba976903030d5 carbon! is possible.

URL’s will follow redirects. In case you need to use it with sites with self-signed/non-trusted certificates you can if you trust the site use --insecure.

Build and run native image (Experimental)

There is support for using native-image from GraalVM project to produce a binary executable.

Since not all java libraries can automatically be built with native-image - especially if using reflection feature are considered highly experimental.

Just run jbang --native helloworld.java and jbang will use native-image from either $JAVA_HOME/bin or $GRAALVM_HOME/bin or $PATH to produce a native image binary.

If you want to have a copy of the generated binary you can run jbang export local -n helloworld.java.

You can install the native-image utility binary e.g. by installing GraalVM from https://www.graalvm.org/downloads, and then once running gu install native-image as per https://www.graalvm.org/reference-manual/native-image.

If you use --native with picocli remember to add info.picocli:picocli-codegen as that will ensure it will actually work with native-image.

Using .jsh for jshell

There is support to run .jsh via jshell. The advantage of jshell is that you do not need to have a class or static main method.

Classic jshell does not support passing in arguments nor system properties, jbang does.

In the case of .jsh files jbang injects a startup script that declares a String[] args which will contain any passed in arguments, and it sets any properties passed in as -Dkey=value as parameters to jbang.

That means you can run a script as jbang -Dkey=value helloworld.jsh World and retrieve arguments and properties as:

System.out.println("Hello " + (args.length>0?args[0]:"World")); (1)
System.out.println(System.getProperty("key")); (2)
1 Line where args are accessible without previous declaration.
2 System properties set when passed as -D arguments to jbang

The script will have the output:

Hello World
value

Please note that .jsh files are source only, they are not compiled thus they are not cached nor can they be built as native images.

If you use -Dkey where no value is specified jbang will interpret this as -Dkey=true allowing you to easily have flags passed into, i.e. jbang -DskipTests mytestrunner.java. Now within your script `Boolean.getBoolean('skipTests') will return true.

Running Kotlin (.kt) (EXPERIMENTAL)

As an experiment since 0.71.0 JBang supports building Kotlin files using kotlinc.

jbang init -t hello.kt hello.kt
./hello.kt
[jbang] Downloading Kotlin 2.0.21. Be patient, this can take several minutes...
[jbang] Installing Kotlin 2.0.21...
[jbang] Resolving dependencies...
[jbang]    org.jetbrains.kotlin:kotlin-stdlib:2.0.21
[jbang] Dependencies resolved
[jbang] Building jar for hello.kt...
Hello World

Running Groovy (.groovy) (EXPERIMENTAL)

As an experiment since 0.85.0 JBang supports building Groovy files using groovyc.

jbang init -t hello.groovy hello.groovy
jbang hello.groovy
[jbang] Downloading Groovy 3.0.9. Be patient, this can take several minutes...
[jbang] Installing Groovy 3.0.9...
[jbang] Resolving dependencies...
[jbang]     Resolving org.codehaus.groovy:groovy:jar:3.0.9...Done
[jbang] Dependencies resolved
[jbang] Building jar...
Hello World

You can control the version of Groovy used via //GROOVY <version> in the script. For example //GROOVY 3.0.19 will use Groovy 3.0.19.

Running Markdowns (.md) (EXPERIMENTAL)

As an experiment since 0.85.0 JBang supports "running" Markdown files (.md)

I.e. if you save the following as readme.md:

## Markdown Scripts

It is possible to write scripts using markdown.

JBang will extract code found in `java` or `jsh` or `jshelllanguage` code blocks.

Try run `jbang readme.md`.

```java
class Demo {
	void test() {
		System.out.println("Hello, World!");
	}
}
```

It will take all blocks and execute via jshell by default and if main method found it will treat it as a .java file.

```jshelllanguage
new Demo().test();
```

You can of course also use `//DEPS` in the code blocks.

```jsh
//DEPS com.github.lalyos:jfiglet:0.0.8
import com.github.lalyos.jfiglet.FigletFont;

System.out.println(FigletFont.convertOneLine(
			"Hello " + ((args.length>0)?args[0]:"jbang")));
```

Oh, and did you notice it handled arguments too?

```java
if(args.length==0) {
	System.out.println("You have no arguments!");
} else {
System.out.printf("You have %s arguments! First is %s", args.length, args[0]);
}
```

You can run it with jbang readme.md YOLO! and give it a result like:

Hello, World!
  _   _          _   _            __   __   ___    _        ___    _
 | | | |   ___  | | | |   ___     \ \ / /  / _ \  | |      / _ \  | |
 | |_| |  / _ \ | | | |  / _ \     \ V /  | | | | | |     | | | | | |
 |  _  | |  __/ | | | | | (_) |     | |   | |_| | | |___  | |_| | |_|
 |_| |_|  \___| |_| |_|  \___/      |_|    \___/  |_____|  \___/  (_)


You have 1 arguments! First is YOLO!%

Running script passed as argument

jbang can run scripts that are passed directly on the command line using the --code option:

jbang --code System.out.println("Hello World!")

Running script from standard input

jbang can run scripts directly from standard input using - or /dev/stdin as input.

i.e. then you can "pipe" the script to jbang:

echo 'System.out.println("Hello World!");' | jbang -

jbang will try and guess if the piped content is a java class and if not assume it it is jshell code. To force jbang to run it as a jshell script you can use --jsh flag.

If you use --interactive jbang will let jshell enter into interactive/REPL mode. You can write /exit to leave this mode. If you are after running .java code via piping or curl it is better to use jbang’s support for running http(s) urls directly, i.e. jbang <urlto-java>.

If your own code needs to handle chained pipes well it is recommended to add the following code:

import sun.misc.Signal;

if (!"Windows".equals(System.getProperty("os.name"))) {
    Signal.handle(new Signal("PIPE"), (final Signal sig) -> System.exit(1));
}

It will give a compiler warning as it is internal API; but for now it works.

Running .jar's

jbang will also run .jar files directly.

i.e. jbang helloworld.jar will run helloworld.jar if found on your local file system.

The .jar can be a local file or a http/https url.

You can also run a .jar file referenced by a Maven coordinate, i.e.:

jbang info.picocli:picocli-codegen:4.6.3

This will fetch the dependency stated and put the transitive dependencies on the class-path.

If you need to specify a main class you can do so by using --main i.e.

jbang --main picocli.codegen.aot.graalvm.ReflectionConfigGenerator info.picocli:picocli-codegen:4.6.3

A side effect of running GAV as a jar, the GAV could also be a .java or .jsh file and it would be launched as a script instead of a jar. No one would want to do that (right?) but now you know.

Usage on Windows

Some JBang commands need to create symbolic links when running on Windows. For example, this is required for editing the files with the edit command.

If you encounter issues on Windows related to the creation of symbolic links follow these instructions:

  1. From Windows 10 onwards you can turn on "Developer Mode", this will automatically enable the possibility to create symbolic links. Read here how to enable this mode: Enable your device for development. On Windows 11 this might already be enabled by default.

  2. If you’re using a Java version equal to or newer than 13 then you’re good to go. This Java version already works correctly. Make sure that JBang is actually using that Java version, either by running java -version to check if the Java on the PATH is version 13 or newer, or if you don’t have Java available on the PATH by running jbang jdk default 13 (or some newer version of course).

  3. If you need symbolic links to work on older Java versions as well, then there is no other option than setting the correct privileges for your user by enabling the Create symbolic links group policy setting. See the instruction on this page for more information on how to do this: Permission to make symbolic links in Windows.