2019-08-09 12:51:42 +00:00
|
|
|
# babashka
|
|
|
|
|
|
|
|
|
|
[](https://circleci.com/gh/borkdude/babashka/tree/master)
|
|
|
|
|
[](https://clojars.org/borkdude/babashka)
|
|
|
|
|
[](https://cljdoc.org/d/borkdude/babashka/CURRENT)
|
|
|
|
|
|
2019-08-09 14:05:14 +00:00
|
|
|
A pure, fast and (severely!) limited version of Clojure in Clojure for shell scripting.
|
2019-08-09 12:51:42 +00:00
|
|
|
|
|
|
|
|
Properties:
|
|
|
|
|
|
|
|
|
|
- pure (no side effects)
|
2019-08-09 13:48:54 +00:00
|
|
|
- fast startup time
|
2019-08-09 12:51:42 +00:00
|
|
|
- interprets only one form
|
|
|
|
|
- reads from stdin and writes to stdout
|
|
|
|
|
|
2019-08-09 17:48:40 +00:00
|
|
|
## Rationale
|
|
|
|
|
|
|
|
|
|
Most of your script is in bash, but you want a tiny sprinkle of Clojure.
|
|
|
|
|
|
|
|
|
|
If most of your shell script evolves into Clojure, you might want to turn to:
|
|
|
|
|
|
|
|
|
|
- [planck](https://planck-repl.org/)
|
|
|
|
|
- [joker](https://github.com/candid82/joker)
|
2019-08-09 21:30:39 +00:00
|
|
|
- [closh](https://github.com/dundalek/closh)
|
2019-08-09 17:48:40 +00:00
|
|
|
- [lumo](https://github.com/anmonteiro/lumo)
|
|
|
|
|
|
2019-08-09 12:51:42 +00:00
|
|
|
## Status
|
|
|
|
|
|
2019-08-09 17:51:45 +00:00
|
|
|
Experimental. Breaking changes are expected to happen at this phase. Not all
|
|
|
|
|
Clojure core functions are supported yet, but can be easily
|
2019-08-09 13:48:54 +00:00
|
|
|
[added](https://github.com/borkdude/babashka/blob/master/src/babashka/interpreter.clj#L10). PRs
|
|
|
|
|
welcome.
|
2019-08-09 12:51:42 +00:00
|
|
|
|
2019-08-09 14:02:08 +00:00
|
|
|
## Installation
|
|
|
|
|
|
|
|
|
|
Linux and macOS binaries are provided via brew.
|
|
|
|
|
|
|
|
|
|
Install:
|
|
|
|
|
|
|
|
|
|
brew install borkdude/brew/babashka
|
|
|
|
|
|
|
|
|
|
Upgrade:
|
|
|
|
|
|
|
|
|
|
brew upgrade babashka
|
|
|
|
|
|
|
|
|
|
You may also download a binary from [Github](https://github.com/borkdude/babashka/releases).
|
|
|
|
|
|
2019-08-09 13:48:54 +00:00
|
|
|
## Usage
|
2019-08-09 12:51:42 +00:00
|
|
|
|
2019-08-09 17:58:11 +00:00
|
|
|
``` shellsession
|
2019-08-09 21:59:19 +00:00
|
|
|
... | bb [--raw] [--println] '<Clojure form>'
|
2019-08-09 17:58:11 +00:00
|
|
|
```
|
|
|
|
|
|
2019-08-09 21:59:19 +00:00
|
|
|
There is one special variable, `*in*`, which is the input read from stdin. The
|
|
|
|
|
input is read as EDN by default, unless the `--raw` flag is provided. When using
|
|
|
|
|
the `--println` flag, the output is printed using `println` instead of `prn`.
|
2019-08-09 12:51:42 +00:00
|
|
|
|
2019-08-10 07:59:46 +00:00
|
|
|
The current version can be printed with `bb --version`.
|
2019-08-09 12:51:42 +00:00
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
|
|
|
|
|
|
``` shellsession
|
2019-08-09 15:38:26 +00:00
|
|
|
$ ls | bb --raw '*in*'
|
|
|
|
|
["LICENSE" "README.md" "bb" "doc" "pom.xml" "project.clj" "reflection.json" "resources" "script" "src" "target" "test"]
|
|
|
|
|
|
2019-08-09 15:40:36 +00:00
|
|
|
$ ls | bb --raw '(count *in*)'
|
2019-08-09 15:38:26 +00:00
|
|
|
11
|
|
|
|
|
|
2019-08-10 07:52:21 +00:00
|
|
|
$ bb '(vec (dedupe *in*))' <<< '[1 1 1 1 2]'
|
2019-08-09 12:51:42 +00:00
|
|
|
[1 2]
|
|
|
|
|
|
2019-08-10 07:52:21 +00:00
|
|
|
$ bb '(filter :foo *in*)' <<< '[{:foo 1} {:bar 2}]'
|
2019-08-09 12:51:42 +00:00
|
|
|
({:foo 1})
|
|
|
|
|
```
|
|
|
|
|
|
2019-08-09 16:17:28 +00:00
|
|
|
Functions are written using the reader tag `#f`. Currently up to three
|
2019-08-09 15:38:26 +00:00
|
|
|
arguments are supported.
|
|
|
|
|
|
|
|
|
|
``` shellsession
|
2019-08-10 07:52:21 +00:00
|
|
|
$ bb '(#f(+ %1 %2 %3) 1 2 *in*)' <<< 3
|
2019-08-09 15:41:33 +00:00
|
|
|
6
|
2019-08-09 16:17:28 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Regexes are written using the reader tag `#r`.
|
2019-08-09 15:38:26 +00:00
|
|
|
|
2019-08-09 16:17:28 +00:00
|
|
|
``` shellsession
|
2019-08-09 21:08:49 +00:00
|
|
|
$ ls | bb --raw '(filterv #f(re-find #r "reflection" %) *in*)'
|
2019-08-09 15:38:26 +00:00
|
|
|
["reflection.json"]
|
|
|
|
|
```
|
|
|
|
|
|
2019-08-09 21:59:19 +00:00
|
|
|
Shuffle the lines of a file:
|
|
|
|
|
|
|
|
|
|
``` shellsession
|
|
|
|
|
$ cat /tmp/test.txt
|
|
|
|
|
1 Hello
|
|
|
|
|
2 Clojure
|
|
|
|
|
3 Babashka
|
|
|
|
|
4 Goodbye
|
|
|
|
|
|
2019-08-10 07:52:21 +00:00
|
|
|
$ < /tmp/test.txt bb --raw '(shuffle *in*)' | bb --println '(str/join "\n" *in*)'
|
2019-08-09 21:59:19 +00:00
|
|
|
3 Babashka
|
|
|
|
|
2 Clojure
|
|
|
|
|
4 Goodbye
|
|
|
|
|
1 Hello
|
|
|
|
|
```
|
|
|
|
|
|
2019-08-09 21:08:49 +00:00
|
|
|
Find the line numbers where the word Clojure occurs using a case insensitive regex:
|
|
|
|
|
|
|
|
|
|
``` shellsession
|
|
|
|
|
$ cat /tmp/test.txt
|
|
|
|
|
foo
|
|
|
|
|
Clojure is nice
|
|
|
|
|
bar
|
|
|
|
|
when you're nice to clojure
|
|
|
|
|
|
2019-08-10 07:52:21 +00:00
|
|
|
$ < /tmp/test.txt bb --raw '(map-indexed #f[%1 %2] *in*))' | \
|
2019-08-09 21:08:49 +00:00
|
|
|
bb '(keep #f(when (re-find #r"(?i)clojure" (second %)) (first %)) *in*)'
|
|
|
|
|
(1 3)
|
|
|
|
|
```
|
|
|
|
|
|
2019-08-09 12:51:42 +00:00
|
|
|
## Test
|
|
|
|
|
|
2019-08-09 18:01:12 +00:00
|
|
|
Test on the JVM:
|
2019-08-09 12:51:42 +00:00
|
|
|
|
|
|
|
|
script/test
|
|
|
|
|
|
2019-08-09 18:01:12 +00:00
|
|
|
Although this tool doesn't offer any benefit when running on the JVM, it is
|
|
|
|
|
convenient for development.
|
|
|
|
|
|
2019-08-09 12:51:42 +00:00
|
|
|
Test the native version:
|
|
|
|
|
|
|
|
|
|
BABASHKA_TEST_ENV=native script/test
|
|
|
|
|
|
|
|
|
|
## Build
|
|
|
|
|
|
|
|
|
|
You will need leiningen and GraalVM.
|
|
|
|
|
|
|
|
|
|
script/compile
|
|
|
|
|
|
|
|
|
|
## License
|
|
|
|
|
|
|
|
|
|
Copyright © 2019 Michiel Borkent
|
|
|
|
|
|
|
|
|
|
Distributed under the EPL License, same as Clojure. See LICENSE.
|