570 lines
16 KiB
Markdown
570 lines
16 KiB
Markdown
# Examples
|
||
|
||
- [Examples](#examples)
|
||
- [Delete a list of files returned by a Unix command](#delete-a-list-of-files-returned-by-a-unix-command)
|
||
- [Calculate aggregate size of directory](#calculate-aggregate-size-of-directory)
|
||
- [Shuffle the lines of a file](#shuffle-the-lines-of-a-file)
|
||
- [Fetch latest Github release tag](#fetch-latest-github-release-tag)
|
||
- [Generate deps.edn entry for a gitlib](#generate-depsedn-entry-for-a-gitlib)
|
||
- [View download statistics from Clojars](#view-download-statistics-from-clojars)
|
||
- [Portable tree command](#portable-tree-command)
|
||
- [List outdated maven dependencies](#list-outdated-maven-dependencies)
|
||
- [Convert project.clj to deps.edn](#convert-projectclj-to-depsedn)
|
||
- [Print current time in California](#print-current-time-in-california)
|
||
- [Tiny http server](#tiny-http-server)
|
||
- [Print random docstring](#print-random-docstring)
|
||
- [Cryptographic hash](#cryptographic-hash)
|
||
- [Package script as Docker image](#package-script-as-docker-image)
|
||
- [Extract single file from zip](#extract-single-file-from-zip)
|
||
- [Note taking app](#note-taking-app)
|
||
- [which](#which)
|
||
- [pom.xml version](#pomxml-version)
|
||
- [Whatsapp frequencies](#whatsapp-frequencies)
|
||
- [Find unused vars](#find-unused-vars)
|
||
- [List contents of jar file](#list-contents-of-jar-file)
|
||
- [Invoke vim inside a script](#invoke-vim-inside-a-script)
|
||
- [Portal](#portal)
|
||
- [Image viewer](#image-viewer)
|
||
- [HTTP server](#http-server)
|
||
- [Torrent viewer](#torrent-viewer)
|
||
- [cprop.clj](#cpropclj)
|
||
- [fzf](#fzf)
|
||
- [digitalocean-ping.clj](#digitalocean-pingclj)
|
||
- [download-aliases.clj](#download-aliasesclj)
|
||
- [Is TTY?](#is-tty)
|
||
- [normalize-keywords.clj](#normalize-keywordsclj)
|
||
- [Check stdin for data](#check-stdin-for-data)
|
||
- [Using org.clojure/data.xml](#using-orgclojuredataxml)
|
||
- [Simple logger](#simple-logger)
|
||
- [Using GZip streams (memo utility)](#using-gzip-streams-to-make-a-note-utility)
|
||
- [Pretty-printing mySQL results](#pretty-printing-mysql-results)
|
||
- [Single page application with Babashka + htmx](#single-page-application-with-babashka--htmx)
|
||
- [Wikipedia translation](#wikipedia-translation)
|
||
|
||
|
||
Here's a gallery of useful examples. Do you have a useful example? PR welcome!
|
||
|
||
## Delete a list of files returned by a Unix command
|
||
|
||
```
|
||
find . | grep conflict | bb -i '(doseq [f *input*] (.delete (io/file f)))'
|
||
```
|
||
|
||
## Calculate aggregate size of directory
|
||
|
||
``` clojure
|
||
#!/usr/bin/env bb
|
||
|
||
(as-> (io/file (or (first *command-line-args*) ".")) $
|
||
(file-seq $)
|
||
(map #(.length %) $)
|
||
(reduce + $)
|
||
(/ $ (* 1024 1024))
|
||
(println (str (int $) "M")))
|
||
```
|
||
|
||
``` shellsession
|
||
$ dir-size
|
||
130M
|
||
|
||
$ dir-size ~/Dropbox/bin
|
||
233M
|
||
```
|
||
|
||
## Shuffle the lines of a file
|
||
|
||
``` shellsession
|
||
$ cat /tmp/test.txt
|
||
1 Hello
|
||
2 Clojure
|
||
3 Babashka
|
||
4 Goodbye
|
||
|
||
$ < /tmp/test.txt bb -io '(shuffle *input*)'
|
||
3 Babashka
|
||
2 Clojure
|
||
4 Goodbye
|
||
1 Hello
|
||
```
|
||
|
||
## Fetch latest Github release tag
|
||
|
||
``` shell
|
||
(require '[clojure.java.shell :refer [sh]]
|
||
'[cheshire.core :as json])
|
||
|
||
(defn babashka-latest-version []
|
||
(-> (sh "curl" "https://api.github.com/repos/babashka/babashka/tags")
|
||
:out
|
||
(json/parse-string true)
|
||
first
|
||
:name))
|
||
|
||
(babashka-latest-version) ;;=> "v0.0.73"
|
||
```
|
||
|
||
## Generate deps.edn entry for a gitlib
|
||
|
||
``` clojure
|
||
#!/usr/bin/env bb
|
||
|
||
(require '[clojure.java.shell :refer [sh]]
|
||
'[clojure.string :as str])
|
||
|
||
(let [[username project branch] *command-line-args*
|
||
branch (or branch "master")
|
||
url (str "https://github.com/" username "/" project)
|
||
sha (-> (sh "git" "ls-remote" url branch)
|
||
:out
|
||
(str/split #"\s")
|
||
first)]
|
||
{:git/url url
|
||
:sha sha})
|
||
```
|
||
|
||
``` shell
|
||
$ gitlib.clj nate fs
|
||
{:git/url "https://github.com/nate/fs", :sha "75b9fcd399ac37cb4f9752a4c7a6755f3fbbc000"}
|
||
$ clj -Sdeps "{:deps {fs $(gitlib.clj nate fs)}}" \
|
||
-e "(require '[nate.fs :as fs]) (fs/creation-time \".\")"
|
||
#object[java.nio.file.attribute.FileTime 0x5c748168 "2019-07-05T14:06:26Z"]
|
||
```
|
||
|
||
## View download statistics from Clojars
|
||
|
||
Contributed by [@plexus](https://github.com/plexus).
|
||
|
||
``` shellsession
|
||
$ curl https://clojars.org/stats/all.edn |
|
||
bb -o '(for [[[group art] counts] *input*] (str (reduce + (vals counts)) " " group "/" art))' |
|
||
sort -rn |
|
||
less
|
||
14113842 clojure-complete/clojure-complete
|
||
9065525 clj-time/clj-time
|
||
8504122 cheshire/cheshire
|
||
...
|
||
```
|
||
|
||
## Portable tree command
|
||
|
||
See [examples/tree.clj](https://github.com/babashka/babashka/blob/master/examples/tree.clj).
|
||
|
||
``` shellsession
|
||
$ clojure -Sdeps '{:deps {org.clojure/tools.cli {:mvn/version "0.4.2"}}}' examples/tree.clj src
|
||
src
|
||
└── babashka
|
||
├── impl
|
||
│ ├── tools
|
||
│ │ └── cli.clj
|
||
...
|
||
|
||
$ examples/tree.clj src
|
||
src
|
||
└── babashka
|
||
├── impl
|
||
│ ├── tools
|
||
│ │ └── cli.clj
|
||
...
|
||
```
|
||
|
||
## List outdated maven dependencies
|
||
|
||
See [examples/outdated.clj](https://github.com/babashka/babashka/blob/master/examples/outdated.clj).
|
||
Inspired by an idea from [@seancorfield](https://github.com/seancorfield).
|
||
|
||
``` shellsession
|
||
$ cat /tmp/deps.edn
|
||
{:deps {cheshire {:mvn/version "5.8.1"}
|
||
clj-http {:mvn/version "3.4.0"}}}
|
||
|
||
$ examples/outdated.clj /tmp/deps.edn
|
||
clj-http/clj-http can be upgraded from 3.4.0 to 3.10.0
|
||
cheshire/cheshire can be upgraded from 5.8.1 to 5.9.0
|
||
```
|
||
|
||
## Convert project.clj to deps.edn
|
||
|
||
Contributed by [@plexus](https://github.com/plexus).
|
||
|
||
``` shellsession
|
||
$ cat project.clj |
|
||
sed -e 's/#=//g' -e 's/~@//g' -e 's/~//g' |
|
||
bb '(let [{:keys [dependencies source-paths resource-paths]} (apply hash-map (drop 3 *input*))]
|
||
{:paths (into source-paths resource-paths)
|
||
:deps (into {} (for [[d v] dependencies] [d {:mvn/version v}]))}) ' |
|
||
jet --pretty > deps.edn
|
||
```
|
||
|
||
A script with the same goal can be found [here](https://gist.github.com/swlkr/3f346c66410e5c60c59530c4413a248e#gistcomment-3232605).
|
||
|
||
## Print current time in California
|
||
|
||
See [examples/pst.clj](https://github.com/babashka/babashka/blob/master/examples/pst.clj)
|
||
|
||
## Tiny http server
|
||
|
||
This implements an http server from scratch. Note that babashka comes with `org.httpkit.server` now, so you don't need to build an http server from scratch anymore.
|
||
|
||
See [examples/http_server_from_scratch.clj](https://github.com/babashka/babashka/blob/master/examples/http_server_from_scratch.clj)
|
||
|
||
Original by [@souenzzo](https://gist.github.com/souenzzo/a959a4c5b8c0c90df76fe33bb7dfe201)
|
||
|
||
## Print random docstring
|
||
|
||
See [examples/random_doc.clj](https://github.com/babashka/babashka/blob/master/examples/random_doc.clj)
|
||
|
||
``` shell
|
||
$ examples/random_doc.clj
|
||
-------------------------
|
||
clojure.core/ffirst
|
||
([x])
|
||
Same as (first (first x))
|
||
```
|
||
|
||
## Cryptographic hash
|
||
|
||
`sha1.clj`:
|
||
``` clojure
|
||
#!/usr/bin/env bb
|
||
|
||
(defn sha1
|
||
[s]
|
||
(let [hashed (.digest (java.security.MessageDigest/getInstance "SHA-1")
|
||
(.getBytes s))
|
||
sw (java.io.StringWriter.)]
|
||
(binding [*out* sw]
|
||
(doseq [byte hashed]
|
||
(print (format "%02X" byte))))
|
||
(str sw)))
|
||
|
||
(sha1 (first *command-line-args*))
|
||
```
|
||
|
||
``` shell
|
||
$ sha1.clj babashka
|
||
"0AB318BE3A646EEB1E592781CBFE4AE59701EDDF"
|
||
```
|
||
|
||
## Package script as Docker image
|
||
|
||
`Dockerfile`:
|
||
``` dockerfile
|
||
FROM babashka/babashka
|
||
RUN echo $'\
|
||
(println "Your command line args:" *command-line-args*)\
|
||
'\
|
||
>> script.clj
|
||
|
||
ENTRYPOINT ["bb", "script.clj"]
|
||
```
|
||
|
||
``` shell
|
||
$ docker build . -t script
|
||
...
|
||
$ docker run --rm script 1 2 3
|
||
Your command line args: (1 2 3)
|
||
```
|
||
|
||
## Extract single file from zip
|
||
|
||
``` clojure
|
||
;; Given the following:
|
||
|
||
;; $ echo 'contents' > file
|
||
;; $ zip zipfile.zip file
|
||
;; $ rm file
|
||
|
||
;; we extract the single file from the zip archive using java.nio:
|
||
|
||
(import '[java.nio.file Files FileSystems CopyOption])
|
||
(let [zip-file (io/file "zipfile.zip")
|
||
file (io/file "file")
|
||
fs (FileSystems/newFileSystem (.toPath zip-file) nil)
|
||
file-in-zip (.getPath fs "file" (into-array String []))]
|
||
(Files/copy file-in-zip (.toPath file)
|
||
(into-array CopyOption [])))
|
||
```
|
||
|
||
## Note taking app
|
||
|
||
See
|
||
[examples/notes.clj](https://github.com/babashka/babashka/blob/master/examples/notes.clj). This
|
||
is a variation on the
|
||
[http-server](https://github.com/babashka/babashka/#tiny-http-server)
|
||
example. If you get prompted with a login, use `admin`/`admin`.
|
||
|
||
## which
|
||
|
||
The `which` command re-implemented in Clojure. See
|
||
[examples/which.clj](https://github.com/babashka/babashka/blob/master/examples/which.clj).
|
||
Prints the canonical file name.
|
||
|
||
``` shell
|
||
$ examples/which.clj rg
|
||
/usr/local/Cellar/ripgrep/11.0.1/bin/rg
|
||
```
|
||
|
||
## pom.xml version
|
||
|
||
A script to retrieve the version from a `pom.xml` file. See
|
||
[pom_version_get.clj](pom_version_get.clj). Written by [@wilkerlucio](https://github.com/wilkerlucio).
|
||
|
||
See [pom_version_get_xml_zip.clj](pom_version_get_xml_zip.clj) for how to do the same using zippers.
|
||
|
||
Also see [pom_version_set.clj](pom_version_set.clj) to set the pom version.
|
||
|
||
## Whatsapp frequencies
|
||
|
||
Show frequencies of messages by user in Whatsapp group chats.
|
||
See [examples/whatsapp_frequencies.clj](whatsapp_frequencies.clj)
|
||
|
||
## Find unused vars
|
||
|
||
[This](hsqldb_unused_vars.clj) script invokes clj-kondo, stores
|
||
returned data in an in memory HSQLDB database and prints the result of a query
|
||
which finds unused vars. It uses
|
||
[pod-babashka-hsqldb](https://github.com/borkdude/pod-babashka-hsqldb).
|
||
|
||
``` shell
|
||
$ bb examples/hsqldb_unused_vars.clj src
|
||
|
||
| :VARS/NS | :VARS/NAME | :VARS/FILENAME | :VARS/ROW | :VARS/COL |
|
||
|----------------------------|--------------------------|------------------------------------|-----------|-----------|
|
||
| babashka.impl.bencode.core | read-netstring | src/babashka/impl/bencode/core.clj | 162 | 1 |
|
||
| babashka.impl.bencode.core | write-netstring | src/babashka/impl/bencode/core.clj | 201 | 1 |
|
||
| babashka.impl.classes | generate-reflection-file | src/babashka/impl/classes.clj | 230 | 1 |
|
||
| babashka.impl.classpath | ->DirectoryResolver | src/babashka/impl/classpath.clj | 12 | 1 |
|
||
| babashka.impl.classpath | ->JarFileResolver | src/babashka/impl/classpath.clj | 37 | 1 |
|
||
| babashka.impl.classpath | ->Loader | src/babashka/impl/classpath.clj | 47 | 1 |
|
||
| babashka.impl.clojure.test | file-position | src/babashka/impl/clojure/test.clj | 286 | 1 |
|
||
| babashka.impl.nrepl-server | stop-server! | src/babashka/impl/nrepl_server.clj | 179 | 1 |
|
||
| babashka.main | -main | src/babashka/main.clj | 485 | 1 |
|
||
```
|
||
|
||
## List contents of jar file
|
||
|
||
For the code see [examples/ls_jar.clj](ls_jar.clj).
|
||
|
||
``` shell
|
||
$ ls_jar.clj borkdude/sci 0.0.13-alpha.24
|
||
META-INF/MANIFEST.MF
|
||
META-INF/maven/borkdude/sci/pom.xml
|
||
META-INF/leiningen/borkdude/sci/project.clj
|
||
...
|
||
```
|
||
|
||
## Invoke vim inside a script
|
||
|
||
See [examples/vim.clj](vim.clj).
|
||
|
||
## Portal
|
||
|
||
This script uses [djblue/portal](https://github.com/djblue/portal/) for inspecting EDN, JSON, XML or YAML files.
|
||
|
||
Example usage:
|
||
|
||
``` shell
|
||
$ examples/portal.clj ~/git/clojure/pom.xml
|
||
```
|
||
|
||
See [portal.clj](portal.clj).
|
||
|
||
## Image viewer
|
||
|
||
Opens browser window and lets user navigate through images of all sub-directories.
|
||
|
||
Example usage:
|
||
|
||
``` shell
|
||
$ examples/image-viewer.clj
|
||
```
|
||
|
||
See [image-viewer.clj](image-viewer.clj).
|
||
|
||
## HTTP Server
|
||
|
||
Opens browser window and lets user navigate through filesystem, similar to
|
||
`python3 -m http.server`.
|
||
|
||
Example usage:
|
||
|
||
``` shell
|
||
$ examples/http-server.clj
|
||
```
|
||
|
||
See [http-server.clj](http-server.clj).
|
||
|
||
## Torrent viewer
|
||
|
||
Shows the content of a torrent file. Note that pieces' content is hidden.
|
||
|
||
Example usage:
|
||
``` shell
|
||
$ examples/torrent-viewer.clj file.torrent
|
||
```
|
||
|
||
See [torrent-viewer.clj](torrent-viewer.clj).
|
||
|
||
## [cprop.clj](cprop.clj)
|
||
|
||
This script uses [tolitius/cprop](https://github.com/tolitius/cprop) library.
|
||
|
||
See [cprop.clj](cprop.clj)
|
||
|
||
Example usage:
|
||
|
||
```shell
|
||
$ ( cd examples && bb cprop.clj )
|
||
```
|
||
|
||
## [fzf](fzf.clj)
|
||
|
||
Invoke [fzf](https://github.com/junegunn/fzf), a command line fuzzy finder, from babashka.
|
||
|
||
See [fzf.clj](fzf.clj)
|
||
|
||
Example usage:
|
||
|
||
``` shell
|
||
$ cat src/babashka/main.clj | bb examples/fzf.clj
|
||
```
|
||
|
||
## [digitalocean-ping.clj](digitalocean-ping.clj)
|
||
|
||
The script allows to define which DigitalOcean cloud datacenter (region) has best network performance (ping latency).
|
||
|
||
See [digitalocean-ping.clj](digitalocean-ping.clj)
|
||
|
||
Example usage:
|
||
|
||
``` shell
|
||
$ bb digitalocean-ping.clj
|
||
```
|
||
|
||
## [download-aliases.clj](download-aliases.clj)
|
||
|
||
Download deps for all aliases in a deps.edn project.
|
||
|
||
## [Is TTY?](is_tty.clj)
|
||
|
||
An equivalent of Python's `os.isatty()` in Babashka, to check if the
|
||
`stdin`/`stdout`/`stderr` is connected to a TTY or not (useful to check if the
|
||
script output is being redirect to `/dev/null`, for example).
|
||
|
||
Only works in Unix systems.
|
||
|
||
``` shell
|
||
$ bb is-tty.clj
|
||
STDIN is TTY?: true
|
||
STDOUT is TTY?: true
|
||
STDERR is TTY?: true
|
||
|
||
$ bb is-tty.clj </dev/null
|
||
STDIN is TTY?: false
|
||
STDOUT is TTY?: true
|
||
STDERR is TTY?: true
|
||
|
||
$ bb is-tty.clj 1>&2 >/dev/null
|
||
STDIN is TTY?: true
|
||
STDOUT is TTY?: false
|
||
STDERR is TTY?: true
|
||
|
||
$ bb is-tty.clj 2>/dev/null
|
||
STDIN is TTY?: true
|
||
STDOUT is TTY?: true
|
||
STDERR is TTY?: false
|
||
```
|
||
|
||
## [normalize-keywords.clj](normalize-keywords.clj)
|
||
|
||
Provide a Clojure file to the script and it will print the Clojure file with
|
||
auto-resolved keywords normalized to fully qualified ones without double colons:
|
||
`::set/foo` becomes `:clojure.set/foo`.
|
||
|
||
``` clojure
|
||
$ cat /tmp/test.clj
|
||
(ns test (:require [clojure.set :as set]))
|
||
|
||
[::set/foo ::bar]
|
||
|
||
$ bb examples/normalize-keywords.clj /tmp/test.clj
|
||
(ns test (:require [clojure.set :as set]))
|
||
|
||
[:clojure.set/foo :test/bar]
|
||
```
|
||
|
||
## Check stdin for data
|
||
|
||
```shell
|
||
# when piping something in, we get a positive number
|
||
$ echo 'abc' | bb '(pos? (.available System/in))'
|
||
true
|
||
# even if we echo an empty string, we still get the newline
|
||
$ echo '' | bb '(pos? (.available System/in))'
|
||
true
|
||
# with nothing passed in, we finally return false
|
||
$ bb '(pos? (.available System/in))'
|
||
false
|
||
```
|
||
|
||
## Using org.clojure/data.xml
|
||
|
||
[xml-example.clj](xml-example.clj) explores some of the capabilities provided
|
||
by the `org.clojure/data.xml` library (required as `xml` by default in Babashka).
|
||
While running the script will show some output, reading the file shows the library
|
||
in use.
|
||
|
||
```shell
|
||
$ bb examples/xml-example.clj
|
||
... some vaguely interesting XML manipulation output
|
||
```
|
||
|
||
## Simple logger
|
||
|
||
[logger.clj](logger.clj) is a simple logger that works in bb.
|
||
|
||
``` clojure
|
||
$ bb "(require 'logger) (logger/log \"the logger says hi\")"
|
||
<expr>:1:19 the logger says hi
|
||
```
|
||
|
||
## Using GZip streams to make a note utility
|
||
|
||
[memo.clj](memo.clj) creates zip files in /tmp for stashing notes (possibly the most inefficient KV store ever)
|
||
|
||
```shell
|
||
$ echo "8675309" | memo.clj put jenny
|
||
ok
|
||
$ memo.clj get jenny
|
||
8675309
|
||
```
|
||
|
||
## Pretty-printing mySQL results
|
||
|
||
[db_who.clj](db_who.clj) will query mysql for all the connected sessions and pretty-print the user and what program they're using.
|
||
|
||
```
|
||
$ bb db_who.clj
|
||
| user | program_name |
|
||
|------------------+----------------|
|
||
| root@localhost | mysql |
|
||
| fred@192.168.1.2 | workbench |
|
||
| jane@192.168.1.3 | Toad for mySQL |
|
||
```
|
||
## Single page application with Babashka + htmx
|
||
|
||
Example of a todo list SPA using Babashka and htmx
|
||
See [htmx_todoapp.clj](htmx_todoapp.clj)
|
||
|
||
Contributed by [@prestancedesign](https://github.com/prestancedesign).
|
||
|
||
## Wikipedia translation
|
||
|
||
[wiki-translate.clj](wiki-translate.clj) uses Wikipedia to translate words from English to Dutch (other languages are available).
|
||
|
||
``` shell
|
||
$ bb wiki-translate.clj window
|
||
"Venster (muur) – Dutch"
|
||
```
|
||
|
||
Shared by Janne Himanka on Clojurians Slack
|