用Bun ShellScript替代Bash:跨平台脚本自动化的新范式

发布时间:2026/7/26 19:50:11
用Bun ShellScript替代Bash:跨平台脚本自动化的新范式 用Bun ShellScript替代Bash跨平台脚本自动化的新范式Bash的痛点跨平台、错误处理、可读性独立开发者常写部署脚本、构建脚本、数据备份脚本——传统选择是Bash。但Bash有三个致命问题跨平台问题Bash在macOS/Linux能跑Windows即使WSL可能有兼容性问题错误处理弱set -e不是默认且错误信息不清晰可读性差if [ -f $file ]; then ...这种语法对新手不友好Bun Shell的解决方案Bun提供了Bun.$API——用TypeScript写Shell脚本且跨平台兼容。Bun Shell核心API比Bash简洁10倍执行命令// 传统Bash // if ! command -v docker /dev/null; then // echo Docker not installed // exit 1 // fi // Bun Shell import { $ } from bun; // 执行命令自动检查失败 try { await $docker ps; } catch (error) { console.error(Docker not running:, error.message); process.exit(1); }管道Pipe// 传统Bashcat access.log | grep 404 | wc -l // Bun Shell const result await $cat access.log | grep 404 | wc -l.text(); console.log(404 errors:, result.trim());重定向// 传统Bashecho Hello output.txt 2 error.log // Bun Shell await $echo Hello.redirect(stdout, output.txt); await $some-command.redirect(stderr, error.log); // 更简洁的语法Bun v1.0.18 await Bun.write(output.txt, $echo Hello);环境变量// 设置环境变量仅对当前命令有效 await $DATABASE_URLpostgres://localhost/myapp npm run db:migrate; // 读取环境变量 console.log(Bun.env.DATABASE_URL);实战用Bun Shell写部署脚本场景部署Next.js应用到VPS用Docker传统Bash版本deploy.sh#!/bin/bash set -e # 任何命令失败就退出 # 1. 检查环境变量 if [ -z $SERVER_IP ]; then echo ERROR: SERVER_IP not set exit 1 fi # 2. 构建Docker镜像 echo Building Docker image... docker build -t myapp:latest . if [ $? -ne 0 ]; then echo ERROR: Docker build failed exit 1 fi # 3. 推送镜像到Docker Hub echo Pushing to Docker Hub... docker push myusername/myapp:latest if [ $? -ne 0 ]; then echo ERROR: Docker push failed exit 1 fi # 4. SSH到服务器拉取并重启容器 echo Deploying to server... ssh user$SERVER_IP ENDSSH docker pull myusername/myapp:latest docker stop myapp || true docker rm myapp || true docker run -d --name myapp -p 3000:3000 myusername/myapp:latest ENDSSH echo Deploy successful!Bun Shell版本deploy.tsimport { $, sleep } from bun; // 1. 检查环境变量类型安全 if (!Bun.env.SERVER_IP) { console.error(ERROR: SERVER_IP not set); process.exit(1); } console.log(Starting deployment...); try { // 2. 构建Docker镜像 console.log(Building Docker image...); await $docker build -t myapp:latest .; // 3. 推送镜像 console.log(Pushing to Docker Hub...); await $docker push myusername/myapp:latest; // 4. SSH部署 console.log(Deploying to server...); await $ssh user${Bun.env.SERVER_IP} ENDSSH docker pull myusername/myapp:latest docker stop myapp || true docker rm myapp || true docker run -d --name myapp -p 3000:3000 --restart unless-stopped myusername/myapp:latest ENDSSH; // 5. 健康检查 console.log(Waiting for health check...); await sleep(5); const health await $curl -s -o /dev/null -w %{http_code} http://${Bun.env.SERVER_IP}:3000/api/health; if (health.stdout.trim() ! 200) { throw new Error(Health check failed: ${health.stdout}); } console.log(✅ Deploy successful!); } catch (error) { console.error(❌ Deploy failed:, error.message); // 自动回滚如果上一版本存在 console.log(Attempting rollback...); await $ssh user${Bun.env.SERVER_IP} docker run -d --name myapp -p 3000:3000 myusername/myapp:previous || true; process.exit(1); }关键改进错误处理清晰try-catch 清晰的错误信息健康检查部署后自动检查失败则回滚类型安全Bun.env.SERVER_IP是string | undefined编译器会提醒你检查实战用Bun Shell写数据库备份脚本场景每天凌晨2点自动备份PostgreSQL数据库到S3Bun Shell版本backup.tsimport { $, cron } from bun; import { S3Client, PutObjectCommand } from aws-sdk/client-s3; const s3 new S3Client({ region: us-east-1 }); async function backupDatabase() { const timestamp new Date().toISOString().split(T)[0]; // YYYY-MM-DD const backupFile backup-${timestamp}.sql; try { console.log(Starting backup: ${backupFile}); // 1. 导出数据库 await $pg_dump $DATABASE_URL ${backupFile}; // 2. 压缩 await $gzip ${backupFile}; const compressedFile ${backupFile}.gz; // 3. 上传到S3 const fileContent await Bun.file(compressedFile).arrayBuffer(); await s3.send(new PutObjectCommand({ Bucket: myapp-backups, Key: daily/${compressedFile}, Body: Buffer.from(fileContent), })); console.log(✅ Backup uploaded: s3://myapp-backups/daily/${compressedFile}); // 4. 清理本地文件保留最近7天 await $find . -name backup-*.sql.gz -mtime 7 -delete; // 5. 清理S3旧备份保留30天 // 用AWS CLI或S3 API删除超过30天的对象 await $aws s3 ls s3://myapp-backups/daily/ | awk {if (NR 30) print $4} | xargs -I {} aws s3 rm s3://myapp-backups/daily/{}; } catch (error) { console.error(❌ Backup failed:, error.message); // 发送告警用Slack Webhook await fetch(Bun.env.SLACK_WEBHOOK_URL!, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ text: Database backup failed: ${error.message}, }), }); process.exit(1); } } // 如果直接运行立即执行 if (import.meta.main) { await backupDatabase(); } // 如果作为模块导入导出给cron使用 export { backupDatabase };设置定时任务用Bun的cron包// cron.ts import { Cron } from bun; import { backupDatabase } from ./backup; // 每天凌晨2点执行 new Cron(0 2 * * *, async () { console.log(Running scheduled backup...); await backupDatabase(); }); console.log(Cron job started: Daily backup at 2:00 AM);运行cron# 用Bun运行会自动保持进程 bun run cron.ts # 或用PM2保持进程 pm2 start bun --name backup-cron -- run cron.ts跨平台兼容性Windows/macOS/LinuxBun Shell的命令会自动转换成当前平台的可执行格式。示例跨平台的文件操作// 这段脚本在Windows/macOS/Linux都能跑 import { $ } from bun; import { mkdir, write } from bun; // 1. 创建目录跨平台 await mkdir(dist, { recursive: true }); // 2. 写入文件 await write(dist/version.txt, 1.0.0); // 3. 执行平台特定的命令 if (process.platform win32) { await $dir dist; } else { await $ls -la dist; }在CI/CD里使用Bun Shell# .github/workflows/deploy.yml name: Deploy on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkoutv3 - name: Install Bun run: | curl -fsSL https://bun.sh/install | bash echo $HOME/.bun/bin $GITHUB_PATH - name: Run deploy script run: bun run scripts/deploy.ts env: SERVER_IP: ${{ secrets.SERVER_IP }} DATABASE_URL: ${{ secrets.DATABASE_URL }}调试技巧让脚本错误一目了然Bun Shell的错误信息比Bash清晰得多// 当命令失败时Bun会抛出清晰的错误 try { await $docker push myusername/myapp:latest; } catch (error) { console.error(Error details:); console.error(- Command:, error.cmd); // 完整的命令 console.error(- Exit code:, error.exitCode); console.error(- Stdout:, error.stdout); console.error(- Stderr:, error.stderr); }用--verbose模式调试// 在脚本开头设置 $.verbose true; // 会打印每个执行的命令 await $docker build -t myapp .; // 会打印 docker build -t myapp .结论Bun Shell是DevOps脚本的未来如果你现在还在写Bash脚本应该考虑迁移到Bun Shell。它的优势跨平台Windows开发Linux部署——没问题类型安全TypeScript帮你避免环境变量未定义等低级错误错误处理try-catch比set -e清晰得多可读性代码即文档新手也能看懂迁移策略新脚本直接用Bun Shell写旧脚本在需要修改时逐步迁移用bun run script.ts替代bash script.sh下一步把你的CI/CD流水线、部署脚本、备份脚本都用Bun Shell重写——你会发现脚本维护从最头疼的事变成最放心的事。