BunShell脚本技能 BunShell

Bun Shell 技能用于在 Bun 环境中通过模板字面量和 spawn API 执行和管理 shell 命令,适用于自动化脚本、进程控制和 DevOps 任务。关键词:Bun Shell, shell 脚本, 子进程管理, Bun 运行时, 自动化。

DevOps 0 次安装 0 次浏览 更新于 3/8/2026

名称: Bun Shell 描述: 使用 Bun.$ 和 Bun.spawn 进行 Bun shell 脚本编写和子进程管理。用于 shell 命令、模板字面量或命令执行。

Bun Shell

Bun 提供了强大的 shell 脚本功能,通过模板字面量和 spawn API。

Bun.$ (Shell 模板)

基本用法

import { $ } from "bun";

// 运行命令
await $`echo "Hello World"`;

// 获取输出
const result = await $`ls -la`.text();
console.log(result);

// JSON 输出
const pkg = await $`cat package.json`.json();
console.log(pkg.name);

变量插值

import { $ } from "bun";

const name = "world";
const dir = "./src";

// 安全插值(转义)
await $`echo "Hello ${name}"`;
await $`ls ${dir}`;

// 数组扩展
const files = ["a.txt", "b.txt", "c.txt"];
await $`touch ${files}`;

管道

import { $ } from "bun";

// 管道命令
const result = await $`cat file.txt | grep "pattern" | wc -l`.text();

// 与 JavaScript 链式使用
const files = await $`ls -la`.text();
const lines = files.split("
").filter(line => line.includes(".ts"));

错误处理

import { $ } from "bun";

// 非零退出时抛出错误
try {
  await $`exit 1`;
} catch (err) {
  console.log(err.exitCode); // 1
  console.log(err.stderr);
}

// 安静模式(不抛出错误)
const result = await $`exit 1`.quiet();
console.log(result.exitCode); // 1

// 检查退出代码
const { exitCode } = await $`grep pattern file.txt`.quiet();
if (exitCode !== 0) {
  console.log("未找到模式");
}

输出类型

import { $ } from "bun";

// 文本
const text = await $`echo hello`.text();

// JSON
const json = await $`cat data.json`.json();

// 行
const lines = await $`ls`.lines();

// Blob
const blob = await $`cat image.png`.blob();

// ArrayBuffer
const buffer = await $`cat binary.dat`.arrayBuffer();

环境变量

import { $ } from "bun";

// 为命令设置环境变量
await $`echo $MY_VAR`.env({ MY_VAR: "value" });

// 访问当前环境变量
$.env.MY_VAR = "value";
await $`echo $MY_VAR`;

// 清除环境变量
await $`env`.env({});

工作目录

import { $ } from "bun";

// 为命令更改目录
await $`pwd`.cwd("/tmp");

// 或全局更改
$.cwd("/tmp");
await $`pwd`;

Bun.spawn

基本生成

const proc = Bun.spawn(["echo", "Hello World"]);
const output = await new Response(proc.stdout).text();
console.log(output); // "Hello World
"

使用选项

const proc = Bun.spawn(["node", "script.js"], {
  cwd: "./project",
  env: {
    NODE_ENV: "production",
    ...process.env,
  },
  stdin: "pipe",
  stdout: "pipe",
  stderr: "pipe",
});

// 写入 stdin
proc.stdin.write("input data
");
proc.stdin.end();

// 读取 stdout
const output = await new Response(proc.stdout).text();
const errors = await new Response(proc.stderr).text();

// 等待退出
const exitCode = await proc.exited;

Stdio 选项

// 继承(使用父进程的 stdio)
Bun.spawn(["ls"], { stdio: ["inherit", "inherit", "inherit"] });

// 管道(捕获输出)
Bun.spawn(["ls"], { stdin: "pipe", stdout: "pipe", stderr: "pipe" });

// 空(忽略)
Bun.spawn(["ls"], { stdout: null, stderr: null });

// 文件(重定向到文件)
Bun.spawn(["ls"], {
  stdout: Bun.file("output.txt"),
  stderr: Bun.file("errors.txt"),
});

流式输出

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

// 同步执行
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 脚本

Shebang 脚本

#!/usr/bin/env bun
import { $ } from "bun";

// 脚本逻辑
const branch = await $`git branch --show-current`.text();
console.log(`当前分支: ${branch.trim()}`);

await $`npm test`;
await $`npm run build`;
chmod +x script.ts
./script.ts

复杂脚本

#!/usr/bin/env bun
import { $ } from "bun";

async function deploy() {
  console.log("🚀 开始部署...");

  // 检查未提交的更改
  const status = await $`git status --porcelain`.text();
  if (status.trim()) {
    console.error("❌ 发现未提交的更改!");
    process.exit(1);
  }

  // 运行测试
  console.log("🧪 运行测试...");
  await $`bun test`;

  // 构建
  console.log("🏗️ 构建...");
  await $`bun run build`;

  // 部署
  console.log("📦 部署...");
  await $`rsync -avz ./dist/ server:/app/`;

  console.log("✅ 部署完成!");
}

deploy().catch((err) => {
  console.error("❌ 部署失败:", err);
  process.exit(1);
});

并行命令

import { $ } from "bun";

// 并行运行
await Promise.all([
  $`npm run lint`,
  $`npm run typecheck`,
  $`npm run test`,
]);

// 或使用 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));

交互式命令

import { $ } from "bun";

// 传递 stdin
const proc = Bun.spawn(["node"], {
  stdin: "inherit",
  stdout: "inherit",
  stderr: "inherit",
});

await proc.exited;

进程管理

const proc = Bun.spawn(["long-running-process"]);

// 杀死进程
proc.kill(); // SIGTERM
proc.kill("SIGKILL"); // 强制杀死

// 检查是否在运行
console.log(proc.killed);

// 获取 PID
console.log(proc.pid);

// 等待超时
const timeout = setTimeout(() => proc.kill(), 5000);
await proc.exited;
clearTimeout(timeout);

常见模式

运行 npm/bun 脚本

import { $ } from "bun";

await $`bun run build`;
await $`bun test`;
await $`bunx tsc --noEmit`;

Git 操作

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 "自动提交"`;
}

文件操作

import { $ } from "bun";

// 查找文件
const files = await $`find . -name "*.ts"`.lines();

// 搜索内容
const matches = await $`grep -r "TODO" src/`.text();

// 存档
await $`tar -czf backup.tar.gz ./data`;

常见错误

错误 原因 修复
命令未找到 不在 PATH 中 使用绝对路径
权限被拒绝 不可执行 chmod +x
退出代码 1 命令失败 检查 stderr
EPIPE 管道损坏 处理进程退出

何时加载参考资料

加载 references/advanced-scripting.md 当:

  • 复杂管道
  • 进程组
  • 信号处理

加载 references/cross-platform.md 当:

  • Windows 兼容性
  • 路径处理
  • Shell 差异