Skip to content

Unleash the power of Java for shell scripting

License

Notifications You must be signed in to change notification settings

stuartwdouglas/jbang

 
 

Repository files navigation

j’bang - Having fun with Java scripting

Release Build Status Che Gitpod

JBang Logo

Intro

Want to learn, explore or use Java instantly without setup ?

Do you like Java but use python, groovy, kotlin or similar languages for your scripts ?

Ever tried out Java 10+ support for running .java files directly in your shell but felt it was a bit too cumbersome ?

Then try jbang which lets you do this:

AVwA19yijKRNKEO0bJENN2ME3

$ jbang init --template=cli hello.java
$ jbang hello.java Max!
[jbang] Resolving dependencies...
[jbang]     Resolving info.picocli:picocli:4.5.0...Done
[jbang] Dependencies resolved
[jbang] Building jar...
Hello Max!
$ jbang hello.java -h
Usage: hello [-hV] <greeting>
hello made with jbang
      <greeting>   The greeting to print
  -h, --help       Show this help message and exit.
  -V, --version    Print version information and exit.

Instant cli app generated built using java and picocli as a dependency that was fetched as needed for the compilation and execution.

Features

  • .java Scripting for Java 8 and upwards

  • .jsh via JShell from Java 9 and upwards

  • Works on [windows] Windows, [apple] OSX and [linux] Linux

  • Install using SDKMan ([apple]/[linux]), Homebrew ([apple]), Chocolatey ([windows]) or Scoop ([windows])

  • Dependency declarations using //DEPS <gav> for automatic dependency resolution

  • Control compile and runtime options with //JAVAC_OPTIONS <flags> and //JAVA_OPTIONS <flags>

  • Compiled jar and Dependency resolution caching

  • (EXPERIMENTAL) native-image generation (--native)

  • Launch with debug enabled for instant debugging from your favorite IDE

  • Transparent launch of JavaFX Applications on Java 8 and higher.

  • Can be used for writing plugins to other cli’s like kubectl

  • Init templates to get started easily (jbang init -t cli hello.java)

  • Generate gradle and IDE config with dependencies for easy editing in your favorite IDE (jbang edit myfile.java)

  • (PLANNED) Lookup dependencies with a short-hand name, i.e. // DEPS log4j:1.2+,picocli for quick getting started.

To use it simply install jbang and run jbang yourscript.java

Requirements

Minimum Java 8, Recommended: Java 11+

Tested and verified to use on OSX, Linux and Windows (incl. command, cygwin and mingw shells).

Installation

To use jbang Java 8 is the minimum required version, however Java 11 or higher is recommended.

SDKMan [linux] / [apple]

To install both java and jbang we recommend sdkman on Linux and OSX.

curl -s "https://get.sdkman.io" | bash # (1)
source ~/.bash_profile # (2)

sdk install java # (3)

Once Java is installed and ready, you install jbang with

sdk install jbang

To test your installation run:

jbang --help

This should print out usage information.

To update run:

sdk update jbang

Chocolatey [windows]

On Windows you can install both java and jbang` with Chocolatey.

From a command prompt with enough rights to install with choco:

choco install jdk11

Once Java in installed run:

choco install jbang

To upgrade to latest version:

choco upgrade jbang

The latest package will be published to jbang choco package page, it might be a bit delayed as the review is still manual. In case the default version is not the latest you can see the version list and install specific version using:

choco install jbang --version=<version number>

Scoop [windows]

On Windows you can also install jbang` with Scoop.

scoop bucket add jbangdev https://github.com/jbangdev/scoop-bucket
scoop install jbang

To upgrade to latest version:

scoop update jbang

Homebrew [apple]

On OSX you can install 'java' and jbang with Homebrew using custom taps.

To install Java 11:

brew tap AdoptOpenJDK/openjdk
brew cask install adoptopenjdk11

Once Java is installed you can use brew with jbangdev/tap to get jbang:

brew install jbangdev/tap/jbang

To upgrade to latest version:

brew upgrade jbangdev/tap/jbang

Installing older versions via Homebrew

If you encounter an issue in jbang that is not present in an older version, you can revert back to that older version following these steps:

  1. Find the commit id for the version to revert to (e.g. 0.8.1).

    $ cd "$(brew --repo jbangdev/tap)"
    $ git log master -- Formula/jbang.rb
    ...
    commit fd70f1bc0a7f69d81cfb5b08a0d2bb698fbd01b2
    Author: Max Rydahl Andersen <[email protected]>
    Date:   Tue Jan 21 00:33:05 2020 +0000
    
        jbang v0.8.1
  2. Checkout the the version.

    $ git checkout fd70f1bc0a7f69d81cfb5b08a0d2bb698fbd01b
  3. Unlink current jbang version.

    $ brew unlink jbang
    Unlinking /usr/local/Cellar/jbang/0.13.2... 1 symlinks removed
  4. Install the older version.

    $ HOMEBREW_NO_AUTO_UPDATE=1 brew install jbang
    ...
    🍺  /usr/local/Cellar/jbang/0.8.1: 18 files, 2.9MB, built in 6 seconds
  5. Verify the version.

    $ jbang version
    0.33.0

(Experimental) Linux packages [linux]

INFO: These builds are not fully automated yet thus might be slightly behind.

You can install rpm packages from Fedora Copr by doing the following:

dnf copr enable maxandersen/jbang
dnf install jbang

The COPR currently includes builds from various versions of CentOS, Fedora, Mageia and OpenSuse.

Docker / GitHub Action [docker]

You can run jbang via Docker:

docker run -v `pwd`:/ws --workdir=/ws jbangdev/jbang-action helloworld.java

or if you prefer using Quay.io:

docker run -v `pwd`:/ws --workdir=/ws quay.io/jbangdev/jbang-action helloworld.java

The same container images can be used with GitHub Actions, see jbang-action for details.

Manual install

Unzip the latest binary release, put the jbang-<version>/bin folder in to your $PATH and you are set.

Usage

A script is just a single .java file with a classic static 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 hellworld.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 run it directly. If you created it manually you need to mark it as executable before running it.

chmod +x helloworld.java
./helloworld jbang!

URLs from Trusted Sources

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

jbang https://github.com/jbangdev/jbang/blob/master/examples/helloworld.java

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://github.com/jbangdev/jbang/blob/master/examples/helloworld.java is not from a trusted source thus aborting.
If you trust the url to be safe to run are here a few suggestions:
Limited trust:
    jbang trust add https://github.com/jbangdev/jbang/
Trust all subdomains:
    jbang trust add *.github.com
Trust all sources (WARNING! disables url protection):
    jbang trust add "*"

For more control edit ~/.jbang/trusted-sources.json

[jbang] Run with --verbose for more details

To enable running it you need to mark that url or a sub part of it as a trusted source. i.e. jbang trust add https://github.com/jbangdev/jbang/ 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, twitter and carbon.now.sh jbang will try and extract the proper source rather than the raw html. i.e. doing jbang https://twitter.com/maxandersen/status/1266904846239752192 twitter! 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 are 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_HPME/bin to produce a native image binary.

💡

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

Using .jsh for jshell

There are 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 with -Dkey=value as parameter to jbang.

Example:

System.out.println("Hello " + (args.length>0?args[0]:"World")); // (1)
System.setProperty("key", "value"); // (2)
  1. Line where args are accessible without previous declaration.

  2. System properties set when passed as -D arguments to jbang

Running script from standard input

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

i.e.

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

If you use `--interactive` `jbang` will let `jshell` enter into interactive/REPL mode. You write `/exit` to leave this mode.
If your own code needs to handle chained pipes well it is recommended to add the following code:

```java
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 (EXPERIMENTAL)

jbang will also run .jar files directly.

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

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

jbang info.picocli:picocli-codegen:4.5.0

This will fetch the dependency stated and put the transitive dependencies on the classpath.

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.5.0

A sideeffect 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.
Noone would want to do that (right?) but now you know.

Init templates

To get started you can run jbang init helloworld.java and a simple java class with a static main is generated.

Using jbang init --template=cli helloworld.java you get a more complete Hello World CLI using picocli as dependencies.

Declare dependencies

If you want to write real scripts you will want to use some java libraries. To specify dependencies you use gradle-style locators or links to Git sources. Below are examples for log4j.

Using //DEPS

//usr/bin/env jbang "$0" "$@" ; exit $?
// (1)
//DEPS log4j:log4j:1.2.17

import static java.lang.System.out;

import org.apache.log4j.Logger;
import org.apache.log4j.BasicConfigurator;

import java.util.Arrays;

class classpath_example {

	static final Logger logger = Logger.getLogger(classpath_example.class);

	public static void main(String[] args) {
		BasicConfigurator.configure(); // (2)
		logger.info("Welcome to jbang");

		Arrays.asList(args).forEach(arg -> logger.warn("arg: " + arg));
		logger.info("Hello from Java!");
	}
}
  1. //DEPS has to be start of line and can be one or more space separated dependencies.

  2. Minimal logging setup - required by log4j.

Now when you run this the first time with no existing dependencies installed you should get an output like this:

$ ./classpath_example.java
[jbang] Resolving dependencies...
[jbang]     Resolving log4j:log4j:1.2.17...Done
[jbang] Dependencies resolved
0 [main] INFO classpath_example  - Welcome to jbang
1 [main] INFO classpath_example  - Hello from Java!

Instead of gradle-style locators you can also use URLs to projects on GitHub, GitLab or BitBucket. Links to those projects will then be converted to references to artifacts on jitpack. You can use links to the root of the project, to the root of a tag/release and to specific commits.

If the project you link to has multiple modules and you want only a specific module you can specify the name of the module by appending #name-of-module to the URL.

And finally if the link you provide is to a specific branch of the project then you need to append #:SNAPSHOT to the URL. (If you have both a branch and a module name then use #name-of-module:SNAPSHOT)

Examples of links and their resulting locator:

Link

Locator

https://github.com/jbangdev/jbang

com.github.jbangdev:jbang:master-SNAPSHOT

https://github.com/jbangdev/jbang/tree/v1.2.3

com.github.jbangdev:jbang:v1.2.3

https://github.com/jbangdev/jbang/tree/f1f34b031…​

com.github.jbangdev:jbang:f1f34b031d

https://github.com/jbangdev/jbang#mymodule

com.github.jbangdev.jbang:mymodule:master-SNAPSHOT

https://github.com/jbangdev/jbang/tree/mybranch#:SNAPSHOT

com.github.jbangdev:jbang:mybranch-SNAPSHOT

https://github.com/jbangdev/jbang/tree/mybranch#mymodule:SNAPSHOT

com.github.jbangdev.jbang.mymodule:mybranch-SNAPSHOT

Offline mode

In case you prefer jbang to just fail-fast when dependencies cannot be found locally you can run jbang in offline mode using jbang -o or jbang --offline. In this mode jbang will simply fail if dependencies have not already been cached already.

Repositories

By default jbang uses jcenter as its repository as it is a superset of Maven Central and supposedly should be faster.

And if you are using the above mentioned URL dependencies jitpack will be added automatically as well.

If that is not sufficient for you or need some custom repo you can use //REPOS id=repourl to state which repository URL to use.

For ease of use there are also a few shorthands to use popular commonly available repositories.

Short name

Description

mavencentral

Maven Central

jcenter

https://jcenter.bintray.com/

google

https://maven.google.com/

jitpack

https://jitpack.io/

Following example enables use of Maven Central and add a custom acme repository.

//REPOS mavenCentral,acme=https://maven.acme.local/maven
⚠️

If you add any //REPOS lines jbang will no longer consult jcenter thus you need to explicitly add it if needed.

💡

For secure authentication jbang will honor ~/.m2/settings-security.xml for configuring username/passwords.

Using @Grab

There is also support for using Groovy lang style @Grab syntax.

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

import static java.lang.System.out;

import org.apache.log4j.Logger;
import org.apache.log4j.BasicConfigurator;

import java.util.Arrays;

import groovy.lang.Grab; // (1)
import groovy.lang.Grapes;
import groovy.lang.GrabResolver;

@GrabResolver("mavenCentral") // (2)
@GrabResolver(name='acme', root='https://maven.acme.local/maven')
@Grapes({ // (3)
		@Grab(group="org.codehaus.groovy", module="groovy", version="2.5.8"), // (4)
		@Grab(module = "log4j", group = "log4j", version = "1.2.17")
})
class classpath_example {

	static final Logger logger = Logger.getLogger(classpath_example.class);

	public static void main(String[] args) {
		BasicConfigurator.configure();
		Arrays.asList(args).forEach(arg -> out.println(arg));
	}
}
  1. Import needed to make the compiler be okey with @Grab annotation.

  2. Using GrabResolver to enable mavenCentral and custom acme repository

  3. In Groovy you normally put @Grab on import statements. That is not allowed in Java thus when having multiple imports you need to put them in a @Grapes annotation first.

  4. jbang will grab any @Grab annotation and assume it is declaring dependencies.

System properties and Environment variables

In dependencies you can refer to environment and system properties to parameterize the dependencies. It uses the format ${[env.]propertyname:<defaultvalue>}.

Furthermore to align with properties commonly used to make dependency resolution portable jbang exposes properties similar to what the os-maven-plugin does. Plus for ease of use for javafx dependencies it also setup a property named ${os.detected.jfxname}.

Examples:

${env.USER} = 'max'
${os.name} = 'Mac OS X'
${non.existing.key:empty} = 'empty'
${os.detected.jfxname} = 'mac'

This can be put to use in //DEPS like so:

//DEPS org.openjfx:javafx-graphics:11.0.2:${os.detected.jfxname}

Here we use the properties to avoid hardcoding your script to a specific operating system.

JavaFX

If jbang detects you have a javafx- dependency in your list of dependencies it will if you java command supports Java modules automatically set the necessary --module-path and --add-modules.

See examples/jfx.java and examples/jfxtiles.java for examples of this.

Extension-less/non-java files for cli-plugins

You can use jbang to write plugins for cli’s like kubectl, git, etc. They expect their plugins to be named like <cmd>-<plugin>, i.e. kubectl-myplugin.

Furthermore some of them, particularly kubectl currently require the file to start with #! otherwise you get a excc format error.

jbang has a bit of auto-magic to help in both cases.

kebab casing of filename

jbang lets you name your file without a .java or .jsh extension, such as kubectl-myplugin. jbang will in this case copy the file to a temporary directory using kebab-case to map the name to a proper java class name.

i.e. If you make a file called kubectl-myplugin then jbang will assume the actual class name to launch will be KubectlMyPlugin.

Note, similar is done when using jbang edit, here the symbolic link will be made so the IDE will treat it as regular camel cased java class.

Note: If you do not follow this naming pattern you will get a compile error as javac expect the public class name are equal to the filename.

she-bang auto-stripped

For extension less scripts, you can put #!' header in beginning to let apps recognize it is to be treated as a script. To avoid issues when compiling `jbang will remove that line before compiling.

For now this is required for kubectl plugin but not git. Issue opened on this limitation.

Java version

jbang will by default first use JAVA_HOME and if not avialble the PATH to locate the java executable to run the script with.

If your script requires a specific or minimal version of Java you can use //JAVA <version>(+).

If jbang finds a java executable using JAVA_HOME or 'PATH which satisfies the stated java version jbang will use it. If no such version is found it will automatically download and install it into jbang’s cache (~/.jbang/cache/jdks by default).

Examples:

//JAVA 11 will force use of Java 11. //JAVA 13+ will require at least java 13. Java 13 or higher will be sued.

In case no matching java is found jbang will fail.

You can always force running with specific version of java using --java command line option, i.e. jbang --java 8 hello.java

Editing

You can edit your script in your IDE by using jbang edit helloworld.java. This will generate a project in a temporary location with symbolic links to your script and output the generated folder name. The easiest way to use that is to use it in a call to your IDE:

code `jbang edit helloworld.java`

If you add additional dependencies to your file just re-run the edit command and the relevant files will be regenerated with the updated dependencies.

📎
On Windows you might need elevated privileges to create symbolic links. If you don’t have permissions then the edit option will result in an error. To use it enable symbolic links for your user or run your shell/terminal as administrator to have this feature working.

Live Editing

You can also use jbang edit --live[=editor] and jbang will launch your editor while watching for file changes and regenerate the temporary project to pick up changes in dependencies.

The editor used will be what is specified as argument to --live or default to $JBANG_EDITOR, $VISUAL or $EDITOR in that order.

IDE and Editor support

The edit feature been tested with the following IDE’s:

Table 1. IDE’s and Editors tested with jbang

50 Visual Studio Code

50 Eclipse

50 IntelliJ Idea

50 Apache NetBeans

50 Neovim w/ spacevim Java

50 Emacs w/ Spacemacs Java

The edit feature works with various IDE’s - it generates a build.gradle to use with IDE’s that understands Gradle directly. For speed and consistency jbang also generates IDE specific settings.

Currently launchers and project files are generated for Eclipse and vscode. Intellij just reads build.gradle for now thus to run/debug you will need to manually set it up.

Debugging

When running .java scripts with jbang you can pass the --debug-flag and the script will enable debug, suspend the execution and wait until you connect a debugger to port 4004.

jbang --debug helloworld.java
Listening for transport dt_socket at address: 4004

You can change the debug port and host by passing in a interface pattern and number to the debug argument, i.e. --debug=*:4321.

This will make it use port 4321 and make it listen on all ('*') network interfaces.

📎
Be sure to put a breakpoint in your IDE/debugger before you connect to make the debugger actually stop when you need it.

Debug jbang it self

java itself will add JAVA_TOOL_OPTIONS which will apply to jbang too.

For finer and more explicit control the scripts for jbang will add JBANG_JAVA_OPTIONS to the call to jbang itself. Thus if you want to enable debug or other details for jbang set that environment variable.

Flight Recorder

Flight recorder is a feature of the Java VM that lets you gather diagnostic and profiling data about your script.

You can use //JAVA_OPTIONS to have full control over it; but for the easiest setup jbang lets you just run with --jfr, i.e.

jbang --jfr myapp.java

By default --jfr will start flight recorder and tell it to dump event recordings to myapp.jfr (i.e. using base name of the script as its filename).

Then you can use tools like jvisualvm or jmc to explore the data.

If you want to tweak the configuration you can pass flightrecorder options, like jbang --jfr=filename={baseName}.jfr,maxage=24h where {baseName} will be replaced by the filename and then added maxage=24h to flight recording options.

If you want further control use //JAVAC_OPTS -XX:StartFlightRecording=<your options> instead.

java and javac Options

If you want to tweak memory settings or enable preview features you can setup the necessary options using //JAVA_OPTS and //COMPILER_OPTS as in the following example using Java 14 experimental record feature:

//usr/bin/env jbang "$0" "$@" ; exit $?
//JAVAC_OPTIONS --enable-preview -source 14 (1)
//JAVA_OPTIONS --enable-preview // (2)

import static java.lang.System.*;

public class records {

    record Point(int x, int y) {}

    public static void main(String[] args) {
        var p = new Point(2,4);
        out.println(p);
    }
}

Since Java 9 JDK_JAVA_OPTIONS and JDK_JAVAC_OPTIONS are also picked up by the Java runtime and compiler automatically.

For Java 8 and if you want to set explicitly only for jbang you can also add flags by setting JBANG_JAVA_OPTIONS and JBANG_JAVAC_OPTIONS respectively.

(Experimental) Application Class Data Sharing

If your scripts uses a lot of classes Class Data Sharing might help on your startup. The following requires Java 13+.

Using --cds jbang will build the jar with Application Class Data Sharing enabled and when run have it load shared class data.

You can put //CDS in the java file to enable it by default, or simply use --cds to force it on or --no-cds to turn it off no matter what the jbang script file contains.

Aliases

To avoid remembering long paths and to enable easy launch of jbang scripts there is an alias command to setup and manage aliases to actual scripts.

will add an alias named hello pointing to that github url which then can be run using jbang hello.

Implicit Alias Catalogs

The aliases managed locally are stored in ~/.jbang/jbang-catalog.json, but jbang can also use remotely catalogs.

Examples:

jbang hello@jbangdev will run the alias hello as defined in jbang-catalog.json found in https://github.com/jbangdev/jbang-catalog.

This allows anyone to provde a set of jbang scripts defined out of their github, gitlab or bitbucket repository.

The full format is <alias>@<user/org>(/repository)(/branch)(~path) allowing you to do things like:

Table 2. Implicit Catalog Examples:
Command Description

jbang hello@acme

hello alias found in acme/jbang-catalog/jbang-catalog.json searched on github, gitlab and bitbucket in that order.

jbang hello@acme/mycatalog`

hello found in acme/mycatalog/jbang-catalog.json searched on github, gitlab and bitbucket in that order.

jbang hello@acme/mycatalog/dev

hello found in acme/mycatalog/jbang-catalog.json in the dev branch searched on github, gitlab and bitbucket in that order.

jbang hello@acme~experimental

hello found in acme/jbang-catalog/experimental/jbang-catalog.json

Bash/Zsh auto-completion

If you are using bash or zsh in your terminal you can get auto-completion by running the following:

source <(jbang completion)

Caching

In previous versions of jbang Java 10+ direct launch of .java was used, but since v0.6 jbang works with Java 8 and thus it needs to do a separate compile step. Besides now working with Java 8 it also allow us to cache the compile step and thus launch faster on consecutive runs.

The caching goes to ~/.jbang/cache by default, you can run jbang cache clear to remove all cache data from this folder.

FAQ

  1. Why the name j’bang?

    I was reading up on how to use the new shebang (#!) feature support in Java 10 and came up with the idea of port kscript to Java and needed a name. From there came j’bang which is a "bad" spelling of how shebang is pronounced in french.

  2. Why use gradle resource locators rather than ?

    kscript used it and it’s nice as it is a one-liner and easily parsable.

  3. How does this compare to ?

    After doing jbang I’ve learned about similar projects and thought it would be nice with some comparison;

    jgo: an alternative way to launch jars using maven coordinates. Implemented in python, depends on Java and Maven to be available. Not really for scripting but a novel way to launch java apps already packaged as a maven dependency.

  4. Why would I use Java to write scripts ? Java sucks for that…​ Use gradle, kotlin, scala, etc. instead!

    Well, does it really suck ? With Java 8 streams, static imports and greatly improved standard java libraries it is very close to what kscript and grape look like. With the following advantages:

    • works with plain Java without installing additional compiler/build tools

    • all IDE’s support editing .java files very well, content assist etc.

    • great debugging

      And to be honest I built jbang just to see if I could and get my Java skills refreshed for the newer features in the language. Use it at your own risk :)

  5. Why not use normal shebang(#!) in the header ?

    You can use normal shebang (#!/usr/bin/env jbang) and Java 10+ will actually work with it from the command line. Not recommended though as many tools and especially IDE’s will start complaining about syntax errors as they don’t ignore the first line in this case.

    By using the // form it is treated as both a bash/shell file AND a valid java file and thus works everywhere a java file will work.

    Its worth noting that Go uses a similar approach which is also where I learned it from.

Thanks

jbang was heavily inspired by how kscript by Holger Brand works.

About

Unleash the power of Java for shell scripting

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Java 84.7%
  • Shell 9.9%
  • Gherkin 2.3%
  • Batchfile 1.6%
  • JavaScript 0.5%
  • Dockerfile 0.5%
  • Other 0.5%