Bun shell scripting with Bun.$, Bun.spawn, subprocess management. Use for shell commands, template literals, or command execution.
Install
npx skillscat add secondsky/claude-skills/bun-shell Install via the SkillsCat registry.
About this skill
This skill enables Bun shell scripting through template literals and subprocess management using Bun.$ and Bun.spawn. It simplifies executing shell commands, handling piping, and parsing command outputs as text, JSON, or binary data. Use this skill when an agent needs to interact with the host operating system or automate command-line workflows.
SKILL.md
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 === 0Shell 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.tsComplex 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