原文地址(Bun Blog): https://bun.sh/blog/the-bun-shell


作者: jarredsumner


发布时间:2024-01-20

前言

JavaScript 是世界上最流行的脚本语言。

那么为什么在 JavaScript 中执行 Shell 脚本很困难呢?

import { spawnSync } from 'child_process'

// 代码比想象中要稍微复杂一些
const { status, stdout, stderr } = spawnSync('ls', ['-l', '*.js'], {
encoding: 'utf8',
})

你也可以使用内置的 API 来执行类似的操作:

import { readdir } from 'fs/promises';

(await readdir('.', { withFileTypes: true })).filter(a =>
a.name.endsWith('.js'),
)

但是,还是没有 shell 脚本简单:

ls *.js

为什么现有的 shell 无法在 JavaScript 中运行

bashsh 等这些 shell 工具已经存在几十年了。

但是,为什么它们在 JavaScript 中不能很好的工作?

macOS (zsh)Linux (bash)Windows (cmd) 的 shell 都有所不同,具有不同的语法和不同的命令。每个平台上可用的命令都不同,甚至相同的命令也可能有不同的可选参数和行为。

迄今为止,npm 的解决方案是依靠社区用 JavaScript 实现来填补缺失的命令。

rm -rf 不适用于 Windows

rimrafrm -rf 指令的跨平台实现,每周下载 6000 万次:

FOO=bar <script> 设置环境变量在 Windows 上不生效

不同平台上设置环境变量的方式略有不同。如果不使用 FOO=bar 这种方式,那就是使用 cross-env

which 在 Windows 上是 where

于是另一个周下载量 6000w 的包诞生了:

shell 启动时间也有一点长

创建一个 shell 执行需要多久?

在 Linux x64 Hetzner Arch Linux 机器上,大约需要 7ms:

$ hyperfine --warmup 3 'bash -c "echo hello"' 'sh -c "echo hello"' -N

Benchmark 1: bash -c 'echo hello'
Time (mean ± σ): 7.3 ms ± 1.5 ms [User: 5.1 ms, System: 1.9 ms]
Range (min … max): 1.7 ms … 9.4 ms 529 runs Benchmark 2: sh -c 'echo hello'
Time (mean ± σ): 7.2 ms ± 1.6 ms [User: 4.8 ms, System: 2.1 ms]
Range (min … max): 1.5 ms … 9.6 ms 327 runs

如果只是想运行单个命令,但是启动 shell 可能比运行命令本身花费更长的时间。如果需要在循环中运行许多命令,那么成本就会升高。

你可以尝试嵌入 shell,但这样就复杂了,而且它们的许可证可能与你的项目不兼容。

这些 polyfill 真的必要吗?

在 2009 - 2016 年的里,JavaScript 还相对较新且处于实验阶段时,依靠社区来填补缺失的功能是很合理的。但现在已经是 2024 年了。JavaScript 已在广泛的使用于服务端开发了。如今,JavaScript 生态系统对需求的理解与 2009 年时完全不同了。

我们其实可以做得更好。

介绍一下 Bun Shell

Bun ShellBun 提供的一种新的实验性的嵌入式语言和解释器,支持使用 JavaScriptTypeScript 编写跨平台运行的 shell 脚本。

import { $ } from 'bun'

// 直接在终端里输出
await $`ls *.js` // 转为字符串变量
const text = await $`ls *.js`.text()

同时允许你使用 JavaScript 变量:

import { $ } from 'bun'

const resp = await fetch('https://example.com')

const stdout = await $`gzip -c < ${resp}`.arrayBuffer()

出于安全问题考虑,所有模板变量都将被转义:

const filename = 'foo.js; rm -rf /'

// 将会执行指令 `ls 'foo.js; rm -rf /'`
const results = await $`ls ${filename}` console.log(results.exitCode) // 1
console.log(results.stderr.toString()) // ls: cannot access 'foo.js; rm -rf /': No such file or directory

使用 Bun Shell 感觉就像普通的 JavaScript。允许你将标准输出放入 buffers 中:

import { $ } from 'bun'

const buffer = Buffer.alloc(1024)

await $`ls *.js > ${buffer}`

console.log(buffer.toString('utf8'))

你也可以将输出结果直接写入文件:

import { $, file } from 'bun'

// 当做文件输出
await $`ls *.js > ${file('output.txt')}` // 或者文件路径字符串
await $`ls *.js > output.txt`
await $`ls *.js > ${'output.txt'}`

你还可以将输出结果通过管道运算符传递给其它命令:

import { $ } from 'bun'

await $`ls *.js | grep foo`

你甚至可以使用 Response 作为标准输入:

import { $ } from 'bun'

const buffer = new Response('bar\n foo\n bar\n foo\n')

await $`grep foo < ${buffer}`

可使用 cdechorm 等内置命令:

import { $ } from 'bun'

await $`cd .. && rm -rf node_modules/rimraf`

它可在 WindowsmacOSLinux 上运行。我们实现了许多常用命令和功能,如通配符环境变量重定向(redirection)管道(piping)等。

它被设计为简单 shell 脚本的替代品。在 WindowsBun 中,它将为 bun run 中的 package.json “脚本”提供支持。

为了更有趣一点,您还可以将它用作独立的 shell 脚本解释器:

echo "cat package.json" > script.bun.sh
bun script.bun.sh

如何安装?

Bun Shell 内置于 Bun 中。如果已经安装了 Bun v1.0.24 或更高版本,那么你就可以使用它:

bun --version
1.0.24

如果你没有安装Bun,可以使用curl安装:

curl -fsSL https://bun.sh/install | bash

或者使用 npm :

npm install -g bun

使用实践

创建 test.ts 文件,写入如下代码

import { $ } from 'bun'

await $`echo hello world`

const files = await $`ls *.js *.mjs`.text()

console.log(files.split('\n'))

运行脚本

bun test.ts

运行结果 如下

译:使用 Bun 执行 Shell 脚本的更多相关文章

  1. Linux中执行shell脚本的4种方法总结

    bash shell 脚本的方法有多种,现在作个小结.假设我们编写好的shell脚本的文件名为hello.sh,文件位置在/data/shell目录中并已有执行权限. 方法一:切换到shell脚本所在 ...

  2. Linux中执行shell脚本的4种方法

    bash shell 脚本的方法有多种,现在作个小结.假设我们编写好的shell脚本的文件名为hello.sh,文件位置在/data/shell目录中并已有执行权限. 方法一:切换到shell脚本所在 ...

  3. 执行shell脚本的几种方法及区别

    执行shell脚本的几种方法及区别 http://blog.csdn.net/lanxinju/article/details/6032368 (认真看) 注意:如果涉及到脚本之间的调用一定要用 . ...

  4. Java SSH远程执行Shell脚本实现(转)

    前言 此程序需要ganymed-ssh2-build210.jar包(下载地址:http://www.ganymed.ethz.ch/ssh2/) 为了调试方便,可以将\ganymed-ssh2-bu ...

  5. JAVA远程执行Shell脚本类

    1.java远程执行shell脚本类 package com.test.common.utility; import java.io.IOException; import java.io.Input ...

  6. 转:linux执行shell脚本的方式及一些区别

    假设shell脚本文件为hello.sh放在/root目录下.下面介绍几种在终端执行shell脚本的方法: [root@localhost home]# cd /root/ [root@localho ...

  7. Java实践 — SSH远程执行Shell脚本(转)

    原文地址:http://www.open-open.com/lib/view/open1384351384024.html 1. SSH简介         SSH是Secure Shell的缩写,一 ...

  8. 每天一个linux命令(62):sh命令 /Linux中执行shell脚本的4种方法总结

    bash shell 脚本的方法有多种,现在作个小结.假设我们编写好的shell脚本的文件名为hello.sh,文件位置在/data/shell目录中并已有执行权限. 方法一:切换到shell脚本所在 ...

  9. SQL Server 中执行Shell脚本计算本地文件的内容大小

    SQL Server 数据库中除了能执行基本的SQL语句外,也可以执行Shell脚本.默认安装后,SQL中的Shell脚本的功能是关闭的,需要手动打开, 执行以下脚本即可打开该功能. -- 允许配置高 ...

  10. 利用python执行shell脚本 并动态传参 及subprocess基本使用

    最近工作需求中 有遇到这个情况  在web端获取配置文件内容 及 往shell 脚本中动态传入参数 执行shell脚本这个有多种方法   最后还是选择了subprocess这个python标准库 su ...

随机推荐

  1. 解决npm 下载速度慢的问题

    更换源,这个是最直接方便 有保障的方法了,不要去安装cnpm,因为你无法确定 他是否做了后门.!! 1. 如果不想安装cnpm 又想使用淘宝服务器来下载扩展插件:(这种方法 每次都得带 废弃) npm ...

  2. [Spring 6.0源码解析] @Configuration注解源码解析

    Spring 6.0源码解析之@Configuration 首先写一个启动代码: public class ConfigurationAnnotationTest { private static f ...

  3. 轻松玩转makefile | 函数的使用

    前言 在上一篇文章中,尽管使用了变量和模式,但还是有不够好的地方,在Makefile中要指明每一个源文件,我们接下来利用函数对其进行优化,并介绍其他常用的一些函数. 依旧是以fun.c ,main.c ...

  4. Ubuntu下利用MWAN+LFTP解除单mac速度限制

    起因 公司网络限制了单个mac地址的速度, 而日常经常需要从线上环境下载几个G的数据到本地, 通过FileZilla每次需要一个多小时, 非常不方便 解决方案 WAN聚合 本地网口连接OpenWRT路 ...

  5. Windows SDK 之 mciSendString最后一个参数

    这里在这里先附上mciSendString的函数原型: MCIERROR mciSendString( LPCTSTR lpszCommand, LPTSTR lpszReturnString, UI ...

  6. springboot中前端ajax如何给controller提交数组参数?

    说明 我有个需求,前端批量添加一堆商品明细.也就是说会有一个商品ID,然后一堆商品明细,多行. 如此一来,针对后端接口肯定是要以数组或列表方式接收这个商品明细数组了. 前端代码 关键地方在于以form ...

  7. PLSQL编译存储过程无响应

    解决方法如下: 1:查V$DB_OBJECT_CACHE SELECT * FROM V$DB_OBJECT_CACHE WHERE name='CRM_LASTCHGINFO_DAY' AND LO ...

  8. 使用xampp安装部署mantis

    快速教程请参考: 点击打开链接   http://download.csdn.net/detail/indexman/6830003 --------------------------- Dylan ...

  9. 解决VMware与win10无法共享目录

    1.安装VMware Tools 这一步适用于多数情况,但对于高版本的VMWare这一步无效,当然了,先试一试总没有坏处. 有看见网上说如果VMware内安装的是高版本的Ubuntu,安装的VMwar ...

  10. 【Android逆向】修改so文件方式修改程序行为

    1. 还是之前的那个apk 链接:https://pan.baidu.com/s/1vKC1SevvHfeI7f0d2c6IqQ 密码:u1an 尝试使用 010Editor来修改so文件 2. 使用 ...