babashka/README.md

254 lines
6 KiB
Markdown
Raw Normal View History

2019-08-13 11:43:15 +00:00
# babashka
2019-08-09 12:51:42 +00:00
[![CircleCI](https://circleci.com/gh/borkdude/babashka/tree/master.svg?style=shield)](https://circleci.com/gh/borkdude/babashka/tree/master)
[![Clojars Project](https://img.shields.io/clojars/v/borkdude/babashka.svg)](https://clojars.org/borkdude/babashka)
[![cljdoc badge](https://cljdoc.org/badge/borkdude/babashka)](https://cljdoc.org/d/borkdude/babashka/CURRENT)
2019-08-12 12:42:45 +00:00
A sprinkle of Clojure for the command line.
## Quickstart
``` shellsession
$ bash <(curl -s https://raw.githubusercontent.com/borkdude/babashka/master/install)
$ bb '(vec (dedupe *in*))' <<< '[1 1 1 1 2]'
[1 2]
```
## Rationale
If you're a bash expert, you probably don't need this. But for those of us who
2019-08-13 22:19:15 +00:00
scan use a bit of Clojure in their shell scripts, it may be useful.
2019-08-09 12:51:42 +00:00
2019-08-15 09:05:59 +00:00
``` shellsession
2019-08-15 09:06:49 +00:00
$ time clj -e "(require '[clojure.java.shell :as shell])" ./script.clj
2019-08-15 09:05:59 +00:00
2.15s user 0.17s system 242% cpu 0.959 total
$ time bb -f ./script.clj
0.00s user 0.00s system 69% cpu 0.010 total
```
2019-08-09 12:51:42 +00:00
## Status
Experimental. Breaking changes are expected to happen at this phase.
2019-08-09 12:51:42 +00:00
2019-08-09 14:02:08 +00:00
## Installation
2019-08-11 07:27:45 +00:00
### Brew
2019-08-09 14:02:08 +00:00
Linux and macOS binaries are provided via brew.
Install:
brew install borkdude/brew/babashka
Upgrade:
brew upgrade babashka
2019-08-11 07:27:45 +00:00
### Installer script
Install via the installer script:
``` shellsession
$ bash <(curl -s https://raw.githubusercontent.com/borkdude/babashka/master/install)
```
By default this will install into `/usr/local/bin`. To change this, provide the directory name:
``` shellsession
$ bash <(curl -s https://raw.githubusercontent.com/borkdude/babashka/master/install) /tmp
```
### Download
2019-08-09 14:02:08 +00:00
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-14 11:38:39 +00:00
bb [ --help ] [ -i ] [ -o ] [ -io ] [ --version ] [ -f <file> ] [ expression ]
2019-08-09 17:58:11 +00:00
```
2019-08-14 11:38:39 +00:00
Type `bb --help` to see a full explanation of the options.
2019-08-15 04:28:00 +00:00
The input is read as EDN by default. If the `-i` flag is provided, then the
input is read as a string which is then split on newlines. The output is printed
as EDN by default, unless the `-o` flag is provided, then the output is turned
into shell-scripting friendly output. To combine `-i` and `-o` you can use
`-io`.
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
2019-08-15 04:28:00 +00:00
Babashka supports a subset of Clojure which is interpreted by
[sci](https://github.com/borkdude/sci).
2019-08-14 11:38:39 +00:00
The `clojure.core` functions are accessible without a namespace alias.
The following Clojure namespaces are required by default and only available
through the aliases:
- `clojure.string` aliased as `str`
- `clojure.set` aliased as `set`
2019-08-14 16:18:23 +00:00
- `clojure.edn` aliased as `edn` (only `read-string` is available)
2019-08-14 11:38:39 +00:00
- `clojure.java.shell` aliases as `shell` (only `sh` is available)
From Java the following is available:
2019-08-13 22:19:15 +00:00
2019-08-15 04:28:00 +00:00
- `System`: `exit`, `getProperty`, `getProperties`, `getenv`
Special vars:
- `*in*`: contains the input read from stdin
- `*command-line-args*`: contain the command line args
2019-08-09 12:51:42 +00:00
Examples:
``` shellsession
$ ls | bb -i '*in*'
2019-08-09 15:38:26 +00:00
["LICENSE" "README.md" "bb" "doc" "pom.xml" "project.clj" "reflection.json" "resources" "script" "src" "target" "test"]
$ ls | bb -i '(count *in*)'
12
2019-08-09 15:38:26 +00:00
$ bb '(vec (dedupe *in*))' <<< '[1 1 1 1 2]'
2019-08-09 12:51:42 +00:00
[1 2]
$ bb '(filterv :foo *in*)' <<< '[{:foo 1} {:bar 2}]'
[{:foo 1}]
2019-08-09 12:51:42 +00:00
```
2019-08-09 15:38:26 +00:00
``` shellsession
$ bb '(#(+ %1 %2 %3) 1 2 *in*)' <<< 3
2019-08-09 15:41:33 +00:00
6
```
``` shellsession
$ ls | bb -i '(filterv #(re-find #"reflection" %) *in*)'
2019-08-09 15:38:26 +00:00
["reflection.json"]
```
2019-08-13 22:19:15 +00:00
``` shellsession
2019-08-14 11:38:39 +00:00
$ bb '(run! #(shell/sh "touch" (str "/tmp/test/" %)) (range 100))'
2019-08-13 22:19:15 +00:00
$ ls /tmp/test | bb -i '*in*'
["0" "1" "10" "11" "12" "13" "14" "15" "16" "17" "18" "19" "2" "20" "21" ...]
```
2019-08-10 20:52:30 +00:00
More examples can be found in the [gallery](#gallery).
2019-08-09 21:08:49 +00:00
2019-08-14 11:38:39 +00:00
## Running a file
Babashka expressions may be executed from a file using `-f` or `--file`:
``` shellsession
2019-08-15 07:08:30 +00:00
bb -f download_html.clj
2019-08-14 11:38:39 +00:00
```
Using `bb` with a shebang also works:
2019-08-15 07:04:14 +00:00
``` clojure
2019-08-15 07:33:11 +00:00
#!/usr/bin/env bb -f
2019-08-15 04:28:00 +00:00
(defn get-url [url]
(println "Fetching url:" url)
(let [{:keys [:exit :err :out]} (shell/sh "curl" "-sS" url)]
(if (zero? exit) out
(do (println "ERROR:" err)
(System/exit 1)))))
(defn write-html [file html]
2019-08-15 07:08:30 +00:00
(println "Writing file:" file)
2019-08-15 04:28:00 +00:00
(spit file html))
(let [[url file] *command-line-args*]
(when (or (empty? url) (empty? file))
(println "Usage: <url> <file>")
(System/exit 1))
(write-html file (get-url url)))
(System/exit 0)
2019-08-14 11:38:39 +00:00
```
2019-08-15 08:41:37 +00:00
``` shellsession
$ ./download_html.clj
Usage: <url> <file>
$ ./download_html.clj https://www.clojure.org /tmp/clojure.org.html
Fetching url: https://www.clojure.org
Writing file: /tmp/clojure.org.html
```
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
2019-08-13 07:20:48 +00:00
## Related projects
- [planck](https://planck-repl.org/)
- [joker](https://github.com/candid82/joker)
- [closh](https://github.com/dundalek/closh)
- [lumo](https://github.com/anmonteiro/lumo)
## Gallery
Here's a gallery of more useful examples. Do you have a useful example? PR
welcome!
2019-08-10 20:52:30 +00:00
### Shuffle the lines of a file
``` shellsession
$ cat /tmp/test.txt
1 Hello
2 Clojure
2019-08-13 11:43:15 +00:00
3 Babashka
2019-08-10 20:52:30 +00:00
4 Goodbye
$ < /tmp/test.txt bb -io '(shuffle *in*)'
2019-08-13 11:43:15 +00:00
3 Babashka
2019-08-10 20:52:30 +00:00
2 Clojure
4 Goodbye
1 Hello
```
### Fetch latest Github release tag
For converting JSON to EDN, see [jet](https://github.com/borkdude/jet).
``` shellsession
2019-08-11 07:05:25 +00:00
$ curl -s https://api.github.com/repos/borkdude/babashka/tags |
2019-08-12 07:28:37 +00:00
jet --from json --keywordize --to edn |
bb '(-> *in* first :name (subs 1))'
2019-08-10 18:34:24 +00:00
"0.0.4"
```
2019-08-10 18:52:13 +00:00
### Get latest OS-specific download url from Github
2019-08-10 18:34:24 +00:00
``` shellsession
2019-08-11 07:05:25 +00:00
$ curl -s https://api.github.com/repos/borkdude/babashka/releases |
2019-08-12 07:28:37 +00:00
jet --from json --keywordize |
bb '(-> *in* first :assets)' |
bb '(some #(re-find #".*linux.*" (:browser_download_url %)) *in*)'
2019-08-10 18:52:13 +00:00
"https://github.com/borkdude/babashka/releases/download/v0.0.4/babashka-0.0.4-linux-amd64.zip"
```
2019-08-09 12:51:42 +00:00
## License
Copyright © 2019 Michiel Borkent
Distributed under the EPL License, same as Clojure. See LICENSE.