Bun Shell 讓使用 JavaScript 和 TypeScript 編寫 Shell 腳本變得有趣。它是一個跨平台的類 bash shell,具有無縫的 JavaScript 互操作性。
快速入門
import { $ } from "bun";
const response = await fetch("https://example.com");
// Use Response as stdin.
await $`cat < ${response} | wc -c`; // 1256
功能:
- 跨平台:可在 Windows、Linux 和 macOS 上運作。您可以使用 Bun Shell,而無需安裝額外的依賴項,取代
rimraf
或cross-env
。常見的 shell 命令,例如ls
、cd
、rm
,均為原生實作。 - 易於上手:Bun Shell 是一個類似 bash 的 shell,支援重新導向、管道、環境變數等。
- Glob 模式:原生支援 Glob 模式,包括
**
、*
、{expansion}
等。 - 模板字串:模板字串用於執行 shell 命令。這使得變數和表達式的內插變得容易。
- 安全:Bun Shell 預設會逸出所有字串,防止 shell 注入攻擊。
- JavaScript 互操作性:可以使用
Response
、ArrayBuffer
、Blob
、Bun.file(path)
和其他 JavaScript 物件作為 stdin、stdout 和 stderr。 - Shell 腳本:Bun Shell 可用於執行 shell 腳本(
.bun.sh
檔案)。 - 自訂直譯器:Bun Shell 是用 Zig 語言編寫的,包括其詞法分析器、語法分析器和直譯器。Bun Shell 是一種小型程式語言。
開始使用
最簡單的 shell 命令是 echo
。要執行它,請使用 $
模板字串標籤
import { $ } from "bun";
await $`echo "Hello World!"`; // Hello World!
預設情況下,shell 命令會列印到 stdout。要靜音輸出,請呼叫 .quiet()
import { $ } from "bun";
await $`echo "Hello World!"`.quiet(); // No output
如果您想以文字形式存取命令的輸出呢?請使用 .text()
import { $ } from "bun";
// .text() automatically calls .quiet() for you
const welcome = await $`echo "Hello World!"`.text();
console.log(welcome); // Hello World!\n
預設情況下,await
將會以 Buffer
形式傳回 stdout 和 stderr。
import { $ } from "bun";
const { stdout, stderr } = await $`echo "Hello!"`.quiet();
console.log(stdout); // Buffer(7) [ 72, 101, 108, 108, 111, 33, 10 ]
console.log(stderr); // Buffer(0) []
錯誤處理
預設情況下,非零的退出碼會拋出錯誤。此 ShellError
包含有關執行命令的資訊。
import { $ } from "bun";
try {
const output = await $`something-that-may-fail`.text();
console.log(output);
} catch (err) {
console.log(`Failed with code ${err.exitCode}`);
console.log(err.stdout.toString());
console.log(err.stderr.toString());
}
可以使用 .nothrow()
停用拋出錯誤。需要手動檢查結果的 exitCode
。
import { $ } from "bun";
const { stdout, stderr, exitCode } = await $`something-that-may-fail`
.nothrow()
.quiet();
if (exitCode !== 0) {
console.log(`Non-zero exit code ${exitCode}`);
}
console.log(stdout);
console.log(stderr);
可以通過在 $
函數本身上呼叫 .nothrow()
或 .throws(boolean)
來配置非零退出碼的預設處理方式。
import { $ } from "bun";
// shell promises will not throw, meaning you will have to
// check for `exitCode` manually on every shell command.
$.nothrow(); // equivalent to $.throws(false)
// default behavior, non-zero exit codes will throw an error
$.throws(true);
// alias for $.nothrow()
$.throws(false);
await $`something-that-may-fail`; // No exception thrown
重新導向
命令的 輸入 或 輸出 可以使用典型的 Bash 運算符進行重新導向
<
重新導向 stdin>
或1>
重新導向 stdout2>
重新導向 stderr&>
重新導向 stdout 和 stderr>>
或1>>
重新導向 stdout,附加到目的地,而不是覆蓋2>>
重新導向 stderr,附加到目的地,而不是覆蓋&>>
重新導向 stdout 和 stderr,附加到目的地,而不是覆蓋1>&2
將 stdout 重新導向到 stderr(所有寫入 stdout 的內容將改為寫入 stderr)2>&1
將 stderr 重新導向到 stdout(所有寫入 stderr 的內容將改為寫入 stdout)
Bun Shell 也支援從 JavaScript 物件重新導向和重新導向到 JavaScript 物件。
範例:將輸出重新導向到 JavaScript 物件 (>
)
要將 stdout 重新導向到 JavaScript 物件,請使用 >
運算符
import { $ } from "bun";
const buffer = Buffer.alloc(100);
await $`echo "Hello World!" > ${buffer}`;
console.log(buffer.toString()); // Hello World!\n
支援重新導向到以下 JavaScript 物件
Buffer
、Uint8Array
、Uint16Array
、Uint32Array
、Int8Array
、Int16Array
、Int32Array
、Float32Array
、Float64Array
、ArrayBuffer
、SharedArrayBuffer
(寫入底層緩衝區)Bun.file(path)
、Bun.file(fd)
(寫入檔案)
範例:從 JavaScript 物件重新導向輸入 (<
)
要將 JavaScript 物件的輸出重新導向到 stdin,請使用 <
運算符
import { $ } from "bun";
const response = new Response("hello i am a response body");
const result = await $`cat < ${response}`.text();
console.log(result); // hello i am a response body
支援從以下 JavaScript 物件重新導向
Buffer
、Uint8Array
、Uint16Array
、Uint32Array
、Int8Array
、Int16Array
、Int32Array
、Float32Array
、Float64Array
、ArrayBuffer
、SharedArrayBuffer
(從底層緩衝區讀取)Bun.file(path)
、Bun.file(fd)
(從檔案讀取)Response
(從 body 讀取)
範例:重新導向 stdin -> 檔案
import { $ } from "bun";
await $`cat < myfile.txt`;
範例:重新導向 stdout -> 檔案
import { $ } from "bun";
await $`echo bun! > greeting.txt`;
範例:重新導向 stderr -> 檔案
import { $ } from "bun";
await $`bun run index.ts 2> errors.txt`;
範例:重新導向 stderr -> stdout
import { $ } from "bun";
// redirects stderr to stdout, so all output
// will be available on stdout
await $`bun run ./index.ts 2>&1`;
範例:重新導向 stdout -> stderr
import { $ } from "bun";
// redirects stdout to stderr, so all output
// will be available on stderr
await $`bun run ./index.ts 1>&2`;
管道 (|
)
就像在 bash 中一樣,您可以將一個命令的輸出通過管道傳送到另一個命令
import { $ } from "bun";
const result = await $`echo "Hello World!" | wc -w`.text();
console.log(result); // 2\n
您也可以使用 JavaScript 物件進行管道傳輸
import { $ } from "bun";
const response = new Response("hello i am a response body");
const result = await $`cat < ${response} | wc -w`.text();
console.log(result); // 6\n
命令替換 ($(...)
)
命令替換允許您將另一個腳本的輸出替換到當前腳本中
import { $ } from "bun";
// Prints out the hash of the current commit
await $`echo Hash of current commit: $(git rev-parse HEAD)`;
這是命令輸出的文字插入,可用於宣告 shell 變數等。
import { $ } from "bun";
await $`
REV=$(git rev-parse HEAD)
docker built -t myapp:$REV
echo Done building docker image "myapp:$REV"
`;
注意:由於 Bun 內部在輸入模板字串上使用了特殊的 raw
屬性,因此使用反引號語法進行命令替換將無法運作
import { $ } from "bun";
await $`echo \`echo hi\``;
而不是印出
hi
上述程式碼將印出
echo hi
我們建議改為堅持使用 $(...)
語法。
環境變數
環境變數可以像在 bash 中一樣設定
import { $ } from "bun";
await $`FOO=foo bun -e 'console.log(process.env.FOO)'`; // foo\n
您可以使用字串內插來設定環境變數
import { $ } from "bun";
const foo = "bar123";
await $`FOO=${foo + "456"} bun -e 'console.log(process.env.FOO)'`; // bar123456\n
輸入預設會被逸出,防止 shell 注入攻擊
import { $ } from "bun";
const foo = "bar123; rm -rf /tmp";
await $`FOO=${foo} bun -e 'console.log(process.env.FOO)'`; // bar123; rm -rf /tmp\n
變更環境變數
預設情況下,process.env
用作所有命令的環境變數。
您可以通過呼叫 .env()
來變更單個命令的環境變數
import { $ } from "bun";
await $`echo $FOO`.env({ ...process.env, FOO: "bar" }); // bar
您可以通過呼叫 $.env
來變更所有命令的預設環境變數
import { $ } from "bun";
$.env({ FOO: "bar" });
// the globally-set $FOO
await $`echo $FOO`; // bar
// the locally-set $FOO
await $`echo $FOO`.env({ FOO: "baz" }); // baz
您可以通過呼叫不帶參數的 $.env()
將環境變數重置為預設值
import { $ } from "bun";
$.env({ FOO: "bar" });
// the globally-set $FOO
await $`echo $FOO`; // bar
// the locally-set $FOO
await $`echo $FOO`.env(undefined); // ""
變更工作目錄
您可以通過將字串傳遞給 .cwd()
來變更命令的工作目錄
import { $ } from "bun";
await $`pwd`.cwd("/tmp"); // /tmp
您可以通過呼叫 $.cwd
來變更所有命令的預設工作目錄
import { $ } from "bun";
$.cwd("/tmp");
// the globally-set working directory
await $`pwd`; // /tmp
// the locally-set working directory
await $`pwd`.cwd("/"); // /
讀取輸出
要將命令的輸出讀取為字串,請使用 .text()
import { $ } from "bun";
const result = await $`echo "Hello World!"`.text();
console.log(result); // Hello World!\n
將輸出讀取為 JSON
要將命令的輸出讀取為 JSON,請使用 .json()
import { $ } from "bun";
const result = await $`echo '{"foo": "bar"}'`.json();
console.log(result); // { foo: "bar" }
逐行讀取輸出
要逐行讀取命令的輸出,請使用 .lines()
import { $ } from "bun";
for await (let line of $`echo "Hello World!"`.lines()) {
console.log(line); // Hello World!
}
您也可以在已完成的命令上使用 .lines()
import { $ } from "bun";
const search = "bun";
for await (let line of $`cat list.txt | grep ${search}`.lines()) {
console.log(line);
}
將輸出讀取為 Blob
要將命令的輸出讀取為 Blob,請使用 .blob()
import { $ } from "bun";
const result = await $`echo "Hello World!"`.blob();
console.log(result); // Blob(13) { size: 13, type: "text/plain" }
內建命令
為了跨平台相容性,Bun Shell 除了從 PATH 環境變數讀取命令外,還實作了一組內建命令。
cd
:變更工作目錄ls
:列出目錄中的檔案rm
:移除檔案和目錄echo
:列印文字pwd
:列印工作目錄bun
:在 bun 中執行 buncat
touch
mkdir
which
mv
exit
true
false
yes
seq
dirname
basename
部分實作
mv
:移動檔案和目錄(缺少跨裝置支援)
尚未實作,但已計畫
- 請參閱 Issue #9716 以取得完整列表。
工具程式
Bun Shell 也實作了一組用於 shell 操作的工具程式。
$.braces
(大括號展開)
此函數為 shell 命令實作了簡單的 大括號展開
import { $ } from "bun";
await $.braces(`echo {1,2,3}`);
// => ["echo 1", "echo 2", "echo 3"]
$.escape
(逸出字串)
將 Bun Shell 的逸出邏輯公開為一個函數
import { $ } from "bun";
console.log($.escape('$(foo) `bar` "baz"'));
// => \$(foo) \`bar\` \"baz\"
如果您不希望字串被逸出,請將其包裝在 { raw: 'str' }
物件中
import { $ } from "bun";
await $`echo ${{ raw: '$(foo) `bar` "baz"' }}`;
// => bun: command not found: foo
// => bun: command not found: bar
// => baz
.sh 檔案載入器
對於簡單的 shell 腳本,您可以使用 Bun Shell 執行 shell 腳本,而無需使用 /bin/sh
。
若要這樣做,只需在具有 .sh
副檔名的檔案上使用 bun
執行腳本即可。
echo "Hello World! pwd=$(pwd)"
bun ./script.sh
Hello World! pwd=/home/demo
使用 Bun Shell 編寫的腳本是跨平台的,這表示它們可以在 Windows 上運作
bun .\script.sh
Hello World! pwd=C:\Users\Demo
實作注意事項
Bun Shell 是 Bun 中的一種小型程式語言,使用 Zig 語言實作。它包含手寫的詞法分析器、語法分析器和直譯器。與 bash、zsh 和其他 shell 不同,Bun Shell 並行執行操作。