Bun Shell
Bun provides powerful shell scripting capabilities with template literals and spawn APIs.
Bun.$ (Shell Template)
Basic Usage
import { $ } from "bun";
// Run command
await $echo "Hello World";
// Get output
const result = await $ls -la.text();
console.log(result);
// JSON output
const pkg = await $cat package.json.json();
console.log(pkg.name);
Variable Interpolation
import { $ } from "bun";
const name = "world"; const dir = "./src";
// Safe interpolation (escaped)
await $echo "Hello ${name}";
await $ls ${dir};
// Array expansion
const files = ["a.txt", "b.txt", "c.txt"];
await $touch ${files};
Piping
import { $ } from "bun";
// Pipe commands
const result = await $cat file.txt | grep "pattern" | wc -l.text();
// Chain with JavaScript
const files = await $ls -la.text();
const lines = files.split("\n").filter(line => line.includes(".ts"));
Error Handling
import { $ } from "bun";
// Throws on non-zero exit
try {
await $exit 1;
} catch (err) {
console.log(err.exitCode); // 1
console.log(err.stderr);
}
// Quiet mode (no throw)
const result = await $exit 1.quiet();
console.log(result.exitCode); // 1
// Check exit code
const { exitCode } = await $grep pattern file.txt.quiet();
if (exitCode !== 0) {
console.log("Pattern not found");
}
Output Types
import { $ } from "bun";
// Text
const text = await $echo hello.text();
// JSON
const json = await $cat data.json.json();
// Lines
const lines = await $ls.lines();
// Blob
const blob = await $cat image.png.blob();
// ArrayBuffer
const buffer = await $cat binary.dat.arrayBuffer();
Environment Variables
import { $ } from "bun";
// Set env for command
await $echo $MY_VAR.env({ MY_VAR: "value" });
// Access current env
$.env.MY_VAR = "value";
await $echo $MY_VAR;
// Clear env
await $env.env({});
Working Directory
import { $ } from "bun";
// Change directory for command
await $pwd.cwd("/tmp");
// Or globally
$.cwd("/tmp");
await $pwd;
Bun.spawn
Basic Spawn
const proc = Bun.spawn(["echo", "Hello World"]); const output = await new Response(proc.stdout).text(); console.log(output); // "Hello World\n"
With Options
const proc = Bun.spawn(["node", "script.js"], { cwd: "./project", env: { NODE_ENV: "production", ...process.env, }, stdin: "pipe", stdout: "pipe", stderr: "pipe", });
// Write to stdin proc.stdin.write("input data\n"); proc.stdin.end();
// Read stdout const output = await new Response(proc.stdout).text(); const errors = await new Response(proc.stderr).text();
// Wait for exit const exitCode = await proc.exited;
Stdio Options
// Inherit (use parent's stdio) Bun.spawn(["ls"], { stdio: ["inherit", "inherit", "inherit"] });
// Pipe (capture output) Bun.spawn(["ls"], { stdin: "pipe", stdout: "pipe", stderr: "pipe" });
// Null (ignore) Bun.spawn(["ls"], { stdout: null, stderr: null });
// File (redirect to file) Bun.spawn(["ls"], { stdout: Bun.file("output.txt"), stderr: Bun.file("errors.txt"), });
Streaming Output
const proc = Bun.spawn(["tail", "-f", "log.txt"], { stdout: "pipe", });
const reader = proc.stdout.getReader(); while (true) { const { done, value } = await reader.read(); if (done) break; console.log(new TextDecoder().decode(value)); }
Bun.spawnSync
// Synchronous execution const result = Bun.spawnSync(["ls", "-la"]);
console.log(result.exitCode); console.log(result.stdout.toString()); console.log(result.stderr.toString()); console.log(result.success); // exitCode === 0
Shell Scripts
Shebang Scripts
#!/usr/bin/env bun import { $ } from "bun";
// Script logic
const branch = await $git branch --show-current.text();
console.log(Current branch: ${branch.trim()});
await $npm test;
await $npm run build;
chmod +x script.ts ./script.ts
Complex Script
#!/usr/bin/env bun import { $ } from "bun";
async function deploy() { console.log("🚀 Starting deployment...");
// Check for uncommitted changes
const status = await $git status --porcelain.text();
if (status.trim()) {
console.error("❌ Uncommitted changes found!");
process.exit(1);
}
// Run tests
console.log("🧪 Running tests...");
await $bun test;
// Build
console.log("🏗️ Building...");
await $bun run build;
// Deploy
console.log("📦 Deploying...");
await $rsync -avz ./dist/ server:/app/;
console.log("✅ Deployment complete!"); }
deploy().catch((err) => { console.error("❌ Deployment failed:", err); process.exit(1); });
Parallel Commands
import { $ } from "bun";
// Run in parallel
await Promise.all([
$npm run lint,
$npm run typecheck,
$npm run test,
]);
// Or with spawn const procs = [ Bun.spawn(["npm", "run", "lint"]), Bun.spawn(["npm", "run", "typecheck"]), Bun.spawn(["npm", "run", "test"]), ];
await Promise.all(procs.map(p => p.exited));
Interactive Commands
import { $ } from "bun";
// Pass through stdin const proc = Bun.spawn(["node"], { stdin: "inherit", stdout: "inherit", stderr: "inherit", });
await proc.exited;
Process Management
const proc = Bun.spawn(["long-running-process"]);
// Kill process proc.kill(); // SIGTERM proc.kill("SIGKILL"); // Force kill
// Check if running console.log(proc.killed);
// Get PID console.log(proc.pid);
// Wait with timeout const timeout = setTimeout(() => proc.kill(), 5000); await proc.exited; clearTimeout(timeout);
Common Patterns
Run npm/bun scripts
import { $ } from "bun";
await $bun run build;
await $bun test;
await $bunx tsc --noEmit;
Git Operations
import { $ } from "bun";
const branch = await $git branch --show-current.text();
const commit = await $git rev-parse HEAD.text();
const status = await $git status --short.text();
if (status) {
await $git add -A;
await $git commit -m "Auto commit";
}
File Operations
import { $ } from "bun";
// Find files
const files = await $find . -name "*.ts".lines();
// Search content
const matches = await $grep -r "TODO" src/.text();
// Archive
await $tar -czf backup.tar.gz ./data;
Common Errors
Error Cause Fix
Command not found
Not in PATH Use absolute path
Permission denied
Not executable chmod +x
Exit code 1
Command failed Check stderr
EPIPE
Broken pipe Handle process exit
When to Load References
Load references/advanced-scripting.md when:
-
Complex pipelines
-
Process groups
-
Signal handling
Load references/cross-platform.md when:
-
Windows compatibility
-
Path handling
-
Shell differences