Awesome
<img src="logo/babashka.svg" width="425px">A Clojure babushka for the grey areas of Bash.
<blockquote class="twitter-tweet" data-lang="en"> <p lang="en" dir="ltr">Life's too short to remember how to write Bash code. I feel liberated.</p> — <a href="https://github.com/laheadle">@laheadle</a> on Clojurians Slack </blockquote>Introduction
The main idea behind babashka is to leverage Clojure in places where you would be using bash otherwise.
As one user described it:
I’m quite at home in Bash most of the time, but there’s a substantial grey area of things that are too complicated to be simple in bash, but too simple to be worth writing a clj/s script for. Babashka really seems to hit the sweet spot for those cases.
Goals
- Fast starting Clojure scripting alternative for JVM Clojure
- Easy installation: grab the self-contained binary and run. No JVM needed.
- Familiar: targeted at JVM Clojure users
- Cross-platform: supports linux, macOS and Windows
- Interop with commonly used classes (
System
,File
,java.time.*
,java.nio.*
) - Multi-threading support (
pmap
,future
) - Batteries included (tools.cli, cheshire, ...)
Non-goals
- Performance
- Provide a mixed Clojure/Bash DSL (see portability).
- Replace existing shells. Babashka is a tool you can use inside existing shells like bash and it is designed to play well with them. It does not aim to replace them.
Quickstart
For installation options check Installation. For quick installation use:
$ bash <(curl -s https://raw.githubusercontent.com/borkdude/babashka/master/install)
or grab a binary from Github releases yourself and place it anywhere on the path.
Then you're ready to go:
$ ls | bb -i '(filter #(-> % io/file .isDirectory) *input*)'
("doc" "resources" "sci" "script" "src" "target" "test")
bb took 4ms.
Babashka users
Are you using babashka in your company or personal projects? Let us know here.
Setting expectations
Babashka uses sci for interpreting Clojure. Sci implements a substantial subset of Clojure. Interpreting code is in general not as performant as executing compiled code. If your script takes more than a few seconds to run or has lots of loops, Clojure on the JVM may be a better fit as the performance on JVM is going to outweigh its startup time penalty. Read more about the differences with Clojure here.
Status
Functionality regarding clojure.core
and java.lang
can be considered stable
and is unlikely to change. Changes may happen in other parts of babashka,
although we will try our best to prevent them. Always check the release notes or
CHANGELOG.md before upgrading.
Talk
To get an overview of babashka, you can watch this talk (slides):
Babashka book
The babashka book contains detailed information about how to get the most out of babashka scripting.
Examples
Read the output from a shell command as a lazy seq of strings:
$ ls | bb -i '(take 2 *input*)'
("CHANGES.md" "Dockerfile")
Read EDN from stdin and write the result to stdout:
$ bb '(vec (dedupe *input*))' <<< '[1 1 1 1 2]'
[1 2]
Read more about input and output flags here.
Execute a script. E.g. print the current time in California using the
java.time
API:
File pst.clj
:
#!/usr/bin/env bb
(def now (java.time.ZonedDateTime/now))
(def LA-timezone (java.time.ZoneId/of "America/Los_Angeles"))
(def LA-time (.withZoneSameInstant now LA-timezone))
(def pattern (java.time.format.DateTimeFormatter/ofPattern "HH:mm"))
(println (.format LA-time pattern))
$ pst.clj
05:17
More examples can be found here.
Try online
You can try babashka online with Nextjournal's babashka notebook environment.
Installation
Brew
Linux and macOS binaries are provided via brew.
Install:
brew install borkdude/brew/babashka
Upgrade:
brew upgrade babashka
Arch (Linux)
babashka
is available in the Arch User Repository. It can be installed using your favorite AUR helper such as
yay, yaourt, apacman and pacaur. Here is an example using yay
:
yay -S babashka-bin
Windows
On Windows you can install using scoop and the scoop-clojure bucket.
Installer script
Install via the installer script:
$ curl -sLO https://raw.githubusercontent.com/borkdude/babashka/master/install
$ chmod +x install
$ ./install
By default this will install into /usr/local/bin
(you may need sudo
for
this). To change this, provide the directory name:
$ ./install --dir /tmp
To install a specific version, the script also supports --version
:
$ ./install --dir /tmp --version 0.2.1
Github releases
You may also download a binary from Github. For linux there is a static binary available which can be used on Alpine.
Docker
Check out the image on Docker hub.
News
Check out the news page to keep track of babashka-related news items.
Built-in namespaces
Go here to see the full list of built-in namespaces.
Projects
A list of projects (scripts, libraries, pods and tools) known to work with babashka.
Pods
Pods are programs that can be used as a Clojure library by babashka. Documentation is available in the pod library repo.
A list of available pods can be found here.
Differences with Clojure
Babashka is implemented using the Small Clojure
Interpreter. This means that a snippet or
script is not compiled to JVM bytecode, but executed form by form by a runtime
which implements a substantial subset of Clojure. Babashka is compiled to
a native binary using GraalVM. It comes with
a selection of built-in namespaces and functions from Clojure and other useful
libraries. The data types (numbers, strings, persistent collections) are the
same. Multi-threading is supported (pmap
, future
).
Differences with Clojure:
-
A pre-selected set of Java classes are supported. You cannot add Java classes at runtime.
-
Interpretation comes with overhead. Therefore loops are slower than in Clojure on the JVM. In general interpretation yields slower programs than compiled programs.
-
No
deftype
,definterface
and unboxed math. -
defprotocol
anddefrecord
are implemented using multimethods and regular maps. Ostensibly they work the same, but under the hood there are no Java classes that correspond to them. -
Currently
reify
works only for one class at a time -
The
clojure.core.async/go
macro is not (yet) supported. For compatibility it currently maps toclojure.core.async/thread
. More info here.
Package babashka script as a AWS Lambda
AWS Lambda runtime doesn't support signals, therefore babashka has to disable
handling of SIGINT and SIGPIPE. This can be done by setting
BABASHKA_DISABLE_SIGNAL_HANDLERS
to true
.
Articles, podcasts and videos
- Babashka and sci internals, a talk by Michiel Borkent at the London Clojurians Meetup.
- Writing Clojure on the Command Line with Babashka, a talk by Nate Jones.
- Using Clojure in Command Line with Babashka, a blog article by Kari Marttila.
- Babashka and GraalVM; taking Clojure to new places, a talk by Michiel Borkent at Clojure/NYC.
- Import a CSV into Kafka, using Babashka by Dave Martin
- Learning about babashka, a blog article by Andrew Montalenti
- Babashka Pods presentation by Michiel Borkent at the Dutch Clojure Meetup.
- AWS Logs using Babashka, a blog published by Toyokumo.
- The REPL podcast Michiel Borkent talks about clj-kondo, Jet, Babashka, and GraalVM with Daniel Compton.
- Implementing an nREPL server for babashka: impromptu presentation by Michiel Borkent at the online Dutch Clojure Meetup
- ClojureScript podcast with Jacek Schae interviewing Michiel Borkent
- Babashka talk at ClojureD (slides) by Michiel Borkent
- Babashka: a quick example by Malcolm Sparks
- Clojure Start Time in 2019 by Stuart Sierra
- Advent of Random Hacks by Arne Brasseur
- Clojure in the Shell by Arne Brasseur
- Clojure Tool by Eric Normand
Building babashka
Developing Babashka
Including new libraries or classes
Before new libraries or classes go into the standardly distributed babashka binary, these evaluation criteria are considered:
- The library or class is useful for general purpose scripting.
- Adding the library or class would make babashka more compatible with Clojure libraries relevant to scripting.
- The library cannot be interpreted by with babashka using
--classpath
. - The functionality can't be met by shelling out to another CLI or can't be
written as a small layer over an existing CLI (like
babashka.curl
) instead. - The library cannot be implemented a pod.
If not all of the criteria are met, but adding a feature is still useful to a
particular company or niche, adding it behind a feature flag is still a
possibility. This is currently the case for next.jdbc
and the PostgresQL
and
HSQLDB
database drivers. Companies interested in these features can compile an
instance of babashka for their internal use. Companies are also free to make
forks of babashka and include their own internal libraries. If their customized
babashka is interesting to share with the world, they are free to distribute it
using a different binary name (like bb-sql
, bb-docker
, bb-yourcompany
,
etc.). See the feature flag documentation and the
implementation of the existing feature flags (example
commit).
Related projects
Contributors
Thanks to all the people that contributed to babashka:
- Adgoji for financial support
- CircleCI for CI and additional support
- Nikita Prokopov for the logo
- Contributors and other users posting issues with bug reports and ideas
- Github sponsors
- OpenCollective sponsors
- Clojurists Together
Code Contributors
This project exists thanks to all the people who contribute. [Contribute]. <a href="https://github.com/borkdude/babashka/graphs/contributors"><img src="https://opencollective.com/babashka/contributors.svg?width=890&button=false" /></a>
Financial Contributors
Become a financial contributor and help us sustain our community. [Contribute]
Individuals
<a href="https://opencollective.com/babashka"><img src="https://opencollective.com/babashka/individuals.svg?width=890"></a>
Organizations
Support this project with your organization. Your logo will show up here with a link to your website. [Contribute]
<a href="https://opencollective.com/babashka/organization/0/website"><img src="https://opencollective.com/babashka/organization/0/avatar.svg"></a> <a href="https://opencollective.com/babashka/organization/1/website"><img src="https://opencollective.com/babashka/organization/1/avatar.svg"></a> <a href="https://opencollective.com/babashka/organization/2/website"><img src="https://opencollective.com/babashka/organization/2/avatar.svg"></a> <a href="https://opencollective.com/babashka/organization/3/website"><img src="https://opencollective.com/babashka/organization/3/avatar.svg"></a> <a href="https://opencollective.com/babashka/organization/4/website"><img src="https://opencollective.com/babashka/organization/4/avatar.svg"></a> <a href="https://opencollective.com/babashka/organization/5/website"><img src="https://opencollective.com/babashka/organization/5/avatar.svg"></a> <a href="https://opencollective.com/babashka/organization/6/website"><img src="https://opencollective.com/babashka/organization/6/avatar.svg"></a> <a href="https://opencollective.com/babashka/organization/7/website"><img src="https://opencollective.com/babashka/organization/7/avatar.svg"></a> <a href="https://opencollective.com/babashka/organization/8/website"><img src="https://opencollective.com/babashka/organization/8/avatar.svg"></a> <a href="https://opencollective.com/babashka/organization/9/website"><img src="https://opencollective.com/babashka/organization/9/avatar.svg"></a>
License
Copyright © 2019-2020 Michiel Borkent
Distributed under the EPL License. See LICENSE.
This project contains code from:
- Clojure, which is licensed under the same EPL License.