Write JavaScript Shell Scripts With Bun

Anthony Rimet
Anthony RimetFebruary 05, 2024
#shell#js

Thanks to Bun Shell, it's now possible to write fast scripts in JavaScript. Some time ago, Alexandre published a test of ZX, a NodeJS wrapper for Bash. This project has inspired many others. For example, Dax was created for Deno and Bnx for Bun. These projects motivated the Bun core team to launch its official version of a Bun wrapper for Bash: Bun Shell.

Before presenting this tool, here's a bit of history.

What Is Bun?

Bun logo

Bun is a JavaScript runtime created by Jarred Summer. Launched in 2021, it aims to create an ecosystem for developing JavaScript/TypeScript applications. It is written in Zig and powered by JavaScriptCore, which considerably reduces startup times and memory usage.

Bun perfs

Claiming to be 4 times faster on startup than Node, this runtime is also compatible with Node. It also converts TypeScript and JSX directly into Vanilla.

Bun is still under development, but it includes a package manager, stacker, bundler, and more.

Bun Shell has just arrived in this ecosystem, and it's very promising.

Bun Shell

$ Shell is a new sub-module that lets developers launch sub-processes using the UNIX syntax. It promises to be cross-platform, running on Windows, MacOS, and Linux.

Let's take a quick look at how to use it. First, you need to install Bun:

curl -fsSL https://bun.sh/install | bash

Other installation methods are available on the documentation.

To have a means of comparison, I'm going to use a little bash script that lets me count the words in a sentence.

#!/bin/bash
response="hello i am a response body"
result=$(echo $response | wc -w)
echo $result

If I convert it to JS and use Bun to execute it, it gives:

#!/usr/bin/env bun
import { $ } from 'bun';
const response = 'hello i am a response body';
const result = await $`echo ${response} | wc -w`.text();
console.log(result); // 6

In this simple example, JavaScript is not necessarily effective for readability and maintainability. For a better example of the transition from bash to JavaScript, see Alexandre's article.

The shebang #!/usr/bin/env bun indicates that we're in a script and defines the interpreter that will execute the command lines.

I won't go into API details here, but you can switch from string output to stdout output by deleting .text() at the end of your command. In this case, we can delete the console.log().

What's interesting is that with Bun as a runner, you can transform this code into TypeScript without any configuration, just by changing the extension.

#!/usr/bin/env bun
import { $ } from 'bun';
const response: string = 'hello i am a response body';
const result: string = await $`echo ${response} | wc -w`.text();
console.log(result); // 6

How Does It Compare To Other Shells?

As I said before, Bun Shell is not the first of its kind. There are already several projects that allow you to run JavaScript in a shell. Our script can be written for Zx like this:

#!/usr/bin/env zx
import { $ } from 'zx';
let response = 'hello i am a response body';
let result = await $`echo ${response} | wc -w`.quiet();
console.log(result.stdout); // 6

Apart from the shebang, there isn't much difference. But what if I told you that Bun shell is 20x faster on this specific script?

benchmark

Bun Shell provides its own implementation of popular UNIX commands such as echo. Some commands are programs, while others are "builtins". Built-in functions are already available in a programming language or a system, without the need for explicit declaration or external libraries. They provide a standardized and efficient way to perform specific tasks. For example, in Bash, echo is a builtin, while wc is a program. Bun Shell provides builtins for commons usage so that they can be executed faster. That's why there's a difference in performance with ZX. Bun covers more common commands, and wants to implement more in the future.

However, as mentioned by Paulus Esterhazy, some of the arguments to these builtins are missing, which makes them difficult to understand.

And Bash remains superior in terms of performance, being around 10-20 times faster than Bun.

Conclusion

As a JS developer, this tool intrigued and seduced me. Being able to write fast scripts in JavaScript and TypeScript, while having good performance and being more readable than Bash, is nice. The Developer Experience (DX) is interesting and will be complete when the main UNIX commands are implemented. I'm excited by the way Bun is turning out.

Once the project is more mature, I'll be happy to use it on React-admin or GreenFrame for my scripts.

approved

Did you like this article? Share it!