jbang을 이용하면 Java 언어를 마치 shell script인 것처럼 사용할 수 있다. jshell
을 이용해도 비슷한 걸 할 수 있지만 script처럼 사용하기에는 jbang이 더 좋아보인다.
설치하기
mac의 경우 brew
를 이용하면 쉽게 설치할 수 있다. 그 외 환경은 install 문서를 참고하자.
$ brew install jbangdev/tap/jbang
Updating Homebrew...
==> Auto-updated Homebrew!
Updated Homebrew from 6da8630f4 to 7e7bdca67.
Updated 2 taps (homebrew/core and homebrew/cask).
==> New Formulae
vue-cli
==> Updated Formulae
Updated 75 formulae.
==> New Casks
sigmaos
==> Updated Casks
Updated 21 casks.
==> Installing jbang from jbangdev/tap
==> Downloading https://github.com/jbangdev/jbang/releases/download/v0.78.0/jbang-0.
Already downloaded: /Users/user/Library/Caches/Homebrew/downloads/9c213ca1805dffaf132ad48ff2475626ea565798f8c427cf44275b10f930d557--jbang-0.78.0.zip
🍺 /usr/local/Cellar/jbang/0.78.0: 7 files, 5.9MB, built in 6 seconds
Hello, Jbang
첫 번째 script를 만들어보자.
아래의 명령을 복붙하여 hello.java
를 만들자.
$ cat <<EOM > hello.java
class hello {
public static void main(String[] args) {
System.out.println("Hello, Jbang");
}
}
EOM
실행 방법 및 결과는 다음과 같다.
$ jbang hello.java
Downloading JBang...
Installing JBang...
[jbang] Building jar...
Hello, Jbang
“Downloading”과 “Installing”은 jbang
을 최초 실행 시에만 출력된다. "Building"
은 소스 코드에 변경이 있을 때마다 실행된다.
마지막 line을 보면 알겠지만 "Hello, Jbang"
잘 출력되었다.
JVM 기반이므로 실행이 약간 굼뜬 것은 어쩔 수 없다. 그리고 javac
후에 java
로 실행하는 것보다도 더 느리다.
본인 환경에서는 위의 간단한 실행을 하는데도 1.4초가 소요된다.
$ time jbang hello.java
Hello, Jbang
real 0m1.426s
user 0m1.495s
sys 0m0.240s
실행 파일 만들기
매번 실행할 때마다 jbang hello.java
입력하기 번거로울 것이다. 일반 스크립트처럼 ./hello.java
만 입력해도 실행할 수 있도록 만들어보자.
hello.java
제일 위 줄을 다음과 같이 만들면 된다.
///usr/bin/env jbang "$0" "$@" ; exit $?
class hello {
public static void main(String[] args) {
System.out.println("Hello, Jbang");
}
}
실행 방법 및 결과는 다음과 같다.
$ ./hello.java
Hello, Jbang
bash에 ///usr/bin/env jbang "$0" "$@" ; exit $?
와 같은 표현이 있는지 모르고 있었다.
어떤 의미인지 궁금하여 검색해보니 Stackexchange에 관련된 글이 있었다.
shell에서 첫 line이 //
로 시작하는 하는 경우 그 뒤에 나오는 문자들을 실행하고, 이후 내용은 무시하라는 것을 의미했다. (호환성을 위해서 ///
처럼 slash 3개를 사용하라고 하는데 정확한 의미는 모르겠다)
따라서 ./hello.java
라고 실행을 하는 경우 실제 실행되는 명령어는 다음과 같다.
$ /usr/bin/env jbang ./hello.java; exit $?
참고로 $0
는 쉘에 입력한 명령을 의미하고 $@
는 argument 전체를 의미하고 $?
는 앞서 실행한 명령의 exit code를 의미한다.
maven 의존성 추가하기
jshell
대비 jbang
의 강력한 기능이다. maven 의존성을 쉽게 추가할 수 있다.
아래의 프로그램은 j-text-utils를 이용한 cli 프로그램이다.
j-text-utils 관련된 코드는 이 문서에 있는 코드를 그대로 사용했다.
다음과 같이 print-peole.java
라는 파일을 만들자
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS com.massisframework:j-text-utils:0.3.4
import dnl.utils.text.table.TextTable;
class Printer {
public static void main(String[] args) {
String[] columnNames = {
"First Name",
"Last Name",
"Sport",
"# of Years",
"Vegetarian"
};
Object[][] data = {
{"Kathy", "Smith", "Snowboarding", new Integer(5), new Boolean(false)},
{"John", "Doe", "Rowing", new Integer(3), new Boolean(true)},
{"Sue", "Black", "Knitting", new Integer(2), new Boolean(false)},
{"Jane", "White", "Speed reading", new Integer(20), new Boolean(true)},
{"Joe", "Brown", "Pool", new Integer(10), new Boolean(false)}
};
TextTable tt = new TextTable(columnNames, data);
// this adds the numbering on the left
tt.setAddRowNumbering(true);
// sort by the first column
tt.setSort(0);
tt.printTable();
}
}
두 번째 line에 있는 //DEPS com.massisframework:j-text-utils:0.3.4
가 의존성을 추가한 것이다.
실행 결과는 다음과 같다.
$ ./print-person.java
[jbang] Resolving dependencies...
[jbang] Resolving com.massisframework:j-text-utils:0.3.4...Done
[jbang] Dependencies resolved
[jbang] Building jar...
______________________________________________________________
| First Name| Last Name| Sport | # of Years| Vegetarian|
|=============================================================|
1. | Jane | White | Speed reading| 20 | true |
2. | Joe | Brown | Pool | 10 | false |
3. | John | Doe | Rowing | 3 | true |
4. | Kathy | Smith | Snowboarding | 5 | false |
5. | Sue | Black | Knitting | 2 | false |
"Resolving dependencies..."
가 출력되면서 의존성 패키지를 다운로드하는 걸 볼 수 있다.
template
template 기반으로 java file을 생성할 수도 있다.
이에 관한 도움말은 templates문서에서 볼 수 있다.
예를 들어 cli 프로그램을 개발한다고 할 때 다음의 명령을 입력하면 기본 구조를 만들어준다.
template 명령 실행
$ jbang init --template=cli helloworld.java
helloworld.java
내용
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS info.picocli:picocli:4.5.0
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Parameters;
import java.util.concurrent.Callable;
@Command(name = "helloworld", mixinStandardHelpOptions = true, version = "helloworld 0.1",
description = "helloworld made with jbang")
class helloworld implements Callable<Integer> {
@Parameters(index = "0", description = "The greeting to print", defaultValue = "World!")
private String greeting;
public static void main(String... args) {
int exitCode = new CommandLine(new helloworld()).execute(args);
System.exit(exitCode);
}
@Override
public Integer call() throws Exception { // your business logic goes here...
System.out.println("Hello " + greeting);
return 0;
}
}
사용 가능한 template은 다음과 같이 조회할 수 있다.
$ jbang template list
agent = Agent template
cli = CLI template
hello = Basic Hello World template
hello.kt = Basic kotlin Hello World template
qcli = Quarkus CLI template
qmetrics = Quarkus Metrics template
qrest = Quarkus REST template
아직 개수는 많지 않다.
또한 자기 자신의 template도 등록할 수 있다. 본인은 테스트해보지 않았다.