Documentation Index
Fetch the complete documentation index at: https://mintlify.com/zhcndoc/bun/llms.txt
Use this file to discover all available pages before exploring further.
Bun includes a built-in, cross-platform shell that you can use directly in JavaScript and TypeScript files. It uses the $ template literal for running shell commands.
Basic Usage
import { $ } from "bun";
// Run a command
await $("echo Hello World");
// Capture output
const output = await $("ls -la").text();
console.log(output);
// Check exit code
const result = await $("git status");
if (result.exitCode === 0) {
console.log("Git working directory is clean");
}
Template Interpolation
Safe Variable Substitution
Variables are automatically escaped:
const filename = "my file.txt";
// Variables are safely quoted
await $("cat ${filename}");
// Executes: cat "my file.txt"
const dir = "/home/user";
const pattern = "*.js";
await $("ls ${dir}/${pattern}");
Raw Strings
Use .raw to pass values without escaping:
const flags = "-la";
await $("ls ${flags.raw}");
// For complex expressions
const sorting = process.env.REVERSE ? "-r" : "";
await $("ls ${sorting.raw} -t");
Piping and Redirection
Pipes
Connect commands with pipes:
await $("cat file.txt | grep pattern | sort | uniq");
// Multi-line for readability
await $(`
cat access.log |
grep ERROR |
wc -l
`);
// Write to file
await $("echo Hello > output.txt");
// Append to file
await $("echo World >> output.txt");
// Read from file
await $("wc -l < input.txt");
// Redirect stderr
await $("command 2> errors.log");
// Redirect both stdout and stderr
await $("command > output.log 2>&1");
Here Documents
await $(`
cat << EOF > config.txt
line 1
line 2
line 3
EOF
`);
Control Flow
Conditional Execution
// AND - run second command only if first succeeds
await $("mkdir temp && cd temp && touch file.txt");
// OR - run second command only if first fails
await $("test -f config.json || cp default.json config.json");
Command Grouping
// Sequential commands
await $("cd src; pwd; ls");
// Background jobs
await $("npm run dev &");
Working with Output
Text Output
const text = await $("cat file.txt").text();
console.log(text);
JSON Output
const data = await $("curl https://api.example.com/data").json();
console.log(data);
Binary Data
const buffer = await $("cat image.png").arrayBuffer();
Line-by-Line
const lines = await $("cat file.txt").lines();
for (const line of lines) {
console.log(line);
}
Streaming
const proc = $("tail -f /var/log/system.log");
for await (const chunk of proc.stdout) {
console.log(new TextDecoder().decode(chunk));
}
Error Handling
Checking Exit Codes
const result = await $("git pull");
if (result.exitCode !== 0) {
console.error("Git pull failed:", result.stderr.toString());
process.exit(1);
}
Exceptions
By default, commands don’t throw on non-zero exit:
// Check manually
const result = await $("false");
console.log(result.exitCode); // 1
// Or use .quiet() to suppress stderr
const result = await $("command-that-might-fail").quiet();
Try/Catch
try {
await $("risky-command");
} catch (err) {
if (err.exitCode) {
console.error(`Command failed with code ${err.exitCode}`);
}
}
Environment Variables
Setting Variables
// For a single command
await $("NODE_ENV=production npm run build");
// Using .env()
const result = await $("node script.js").env({
NODE_ENV: "production",
API_KEY: process.env.API_KEY,
});
Accessing Variables
const home = await $("echo $HOME").text();
console.log(home.trim());
Options
Change Directory
await $("ls").cwd("/tmp");
// Or inline
await $("cd /tmp && ls");
Quiet Mode
Suppress stderr output:
const result = await $("command").quiet();
Nothrow
Prevent throwing on errors:
const result = await $("might-fail").nothrow();
if (!result.success) {
console.log("Command failed but we handled it");
}
Built-in Commands
Bun’s shell includes cross-platform implementations of common commands:
cd - Change directory
echo - Print text
ls - List files
cat - Concatenate files
rm - Remove files
mkdir - Create directories
mv - Move files
cp - Copy files
pwd - Print working directory
which - Locate commands
exit - Exit with code
These work identically on Windows, macOS, and Linux.
Advanced Features
Glob Patterns
// Match multiple files
await $("cat src/**/*.ts | wc -l");
// Brace expansion
await $("touch file{1,2,3}.txt");
Command Substitution
const count = await $("ls | wc -l").text();
await $("echo There are ${count} files");
Process Substitution
// Compare outputs
await $("diff <(ls dir1) <(ls dir2)");
Running Scripts
Inline Scripts
import { $ } from "bun";
await $(`
echo "Starting build..."
rm -rf dist
mkdir -p dist
bun build src/index.ts --outdir dist
echo "Build complete!"
`);
Script Files
Create executable shell scripts with Bun:
#!/usr/bin/env bun
import { $ } from "bun";
const branch = await $("git branch --show-current").text();
console.log(`Current branch: ${branch.trim()}`);
if (branch.includes("main")) {
console.log("Deploying to production...");
await $("npm run deploy:prod");
} else {
console.log("Deploying to staging...");
await $("npm run deploy:staging");
}
Make it executable:
chmod +x deploy.ts
./deploy.ts
Bun’s shell is optimized for:
- Fast startup - No subprocess overhead for built-in commands
- Memory efficiency - Streams data instead of buffering
- Concurrent execution - Multiple commands run in parallel where possible
Differences from Bash
Not a Full Shell
Bun’s shell supports common scripting patterns but is not POSIX-compliant:
- No functions or aliases
- Limited job control
- Simplified parameter expansion
Web Standards
Bun uses Web APIs:
ReadableStream instead of Unix pipes
TextDecoder for encoding
fetch() for HTTP
vs. Node.js child_process
// Bun Shell - concise
await $("ls | grep .ts | wc -l");
// Node - verbose
const { spawn } = require('child_process');
const ls = spawn('ls');
const grep = spawn('grep', ['.ts']);
const wc = spawn('wc', ['-l']);
ls.stdout.pipe(grep.stdin);
grep.stdout.pipe(wc.stdin);
vs. Zx (Google)
Bun’s shell is similar to zx but:
- Built-in (no extra dependency)
- Faster (no subprocess for simple commands)
- Cross-platform (works on Windows natively)
Best Practices
-
Use template literals for readability
await $(`
npm install &&
npm run build &&
npm test
`);
-
Check exit codes for critical commands
const result = await $("npm test");
if (result.exitCode !== 0) process.exit(1);
-
Stream large outputs
for await (const line of $("tail -f log.txt").lines()) {
console.log(line);
}
-
Use quiet mode for noisy commands
await $("npm install").quiet();