@aliou/sh

中文文档
0.4.0发布于 2026/11/05MIT AND BSD-3-ClauseTypeScriptES Module零依赖构建来源已验证近 30 天下载 6899

POSIX/Bash/mksh/zsh的外壳解析器/AST(WIP)

中文使用文档
文档目录10 节
  1. 安装
  2. 快开始
  3. 示例:旗下危险命令
  4. 选项
  5. 懒惰分析
  6. 其他出口
  7. 支持的语法
  8. 状态
  9. 发展
  10. 许可证

@aliou/sh (韩语)

外壳解析器并输入了TypeScript的AST. 处理POSIX, Bash, mksh, 和zsh语法. 0运行时依赖,~66 KB捆绑.

安装

npm install @aliou/sh

需要节点.js 22+.

快开始

import { parse } from "@aliou/sh";

const { ast } = parse('echo "hello $USER" | grep hello');
// ast.type === "Program"
// ast.body[0].command.type === "Pipeline"

parse 返回 a Program 他的身体拥有 Statement 节点。 每个语句都包裹着一个 Command数字 :

命令Shell 语法
SimpleCommand单词、任务、重定向
Pipelinea | b
Logicala && b, (中文(简体) ), a || b
IfClause, (中文(简体) ), WhileClause, (中文(简体) ), ForClause, (中文(简体) ), SelectClause, (中文(简体) ), CaseClause控制流量
FunctionDeclfoo() {}, (中文(简体) ), function foo {}
Subshell, (中文(简体) ), Block( ... ), (中文(简体) ), { ... }
TestClause, (中文(简体) ), ArithCmd[[ ... ]], (中文(简体) ), (( ... ))
CoprocClause, (中文(简体) ), TimeClausecoproc, (中文(简体) ), time
DeclClausedeclare, (中文(简体) ), local, (中文(简体) ), export, (中文(简体) ), readonly, (中文(简体) ), typeset, (中文(简体) ), nameref
LetClauselet i++ j=2
CStyleLoopfor (( ; ; ))

单词持有打入的部分 : Literal, (中文(简体) ), SglQuoted, (中文(简体) ), DblQuoted, (中文(简体) ), ParamExp, (中文(简体) ), CmdSubst, (中文(简体) ), ArithExp, (中文(简体) ), ProcSubst, (中文(简体) ), BraceExp, (中文(简体) ), ExtGlob。每个节点携带 pos 财务报告和审定财务报表 end (单位:千美元)offset, (中文(简体) ), line, (中文(简体) ), col)指入出处.

示例:旗下危险命令

每个节点 type 字段缩小了结合,所以一般行走者可以捕捉到任何出现的特定的指令——管道, && 链、子壳、命令替换:

import { parse, type SimpleCommand } from "@aliou/sh";

function findRmRf(node: unknown): string[] {
  if (!node || typeof node !== "object") return [];

  const cmd = node as SimpleCommand;
  if (cmd.type === "SimpleCommand") {
    const [name, ...args] = (cmd.words ?? [])
      .map((w) => (w.parts[0].type === "Literal" ? w.parts[0].value : ""))
      .filter(Boolean);
    if (name === "rm" && args.some((a) => a.startsWith("-") && a.includes("r") && a.includes("f"))) {
      return [`rm ${args.join(" ")}`];
    }
  }

  return Object.values(cmd).flatMap((v) =>
    Array.isArray(v) ? v.flatMap(findRmRf) : findRmRf(v),
  );
}

const { ast } = parse("deploy.sh && rm -rf ./scratch; cp -r dist/ b/ || (rm -rf b/ && exit 1)");
findRmRf(ast); // ["rm -rf ./scratch", "rm -rf b/"]

这种检查是项目的主要使用案例:检查或重写命令,然后将脚本交给执行它的东西.

选项

interface ParseOptions {
  dialect?: "posix" | "bash" | "mksh" | "zsh"; // default: "bash"
  keepComments?: boolean; // default: false
  recoverErrors?: boolean; // default: false
}

设定 recoverErrors: true 获取部分 AST + a errors 数组而不是被丢弃的例外 。 用于分析不完整或已断开的脚本(编辑器,linters).

懒惰分析

对于大型脚本,流顶级节点不构建整个AST:

import { parseStmtsSeq, parseWordsSeq } from "@aliou/sh";

for (const stmt of parseStmtsSeq(source)) { /* one statement at a time */ }
for (const word of parseWordsSeq(source)) { /* one word at a time */ }

其他出口

  • splitBraces(word) 扩大 {a,b} 编号 : {1..5} 支撑扩张成一个字。 解析器默认不会释放括号扩展 .
  • NO_POS ——你手建的节点的哨站位置.
  • 每个AST节点的完整类型脚本.

支持的语法

  • 简单的指令,管道, &&, (中文(简体) ), ||页:1&),分号
  • 引证: '...', (中文(简体) ), "...",反弹续作
  • 参数扩展: $var, (中文(简体) ), ${var:-default}, (中文(简体) ), ${var/pat/repl}切片,间接
  • 命令替换 : $(cmd), (中文(简体) ), `cmd`
  • 算术: $((expr)), (中文(简体) ), ((expr)), C 样式 for (( ; ; ))
  • 进程替换 : <(cmd), (中文(简体) ), >(cmd)
  • 此处文件( E)<<, (中文(简体) ), <<-)和花边(<<<(中文(简体) )
  • 重定向 : >, (中文(简体) ), >>, (中文(简体) ), <, (中文(简体) ), >&, (中文(简体) ), <&, (中文(简体) ), <>, (中文(简体) ), >|, (中文(简体) ), &>, (中文(简体) ), &>>附加时 {varname} fd 重定向( Bash/zsh)
  • 任务和附件 : FOO=bar, (中文(简体) ), FOO+=bar,命令范围
  • 矩阵 : arr=(a b c), (中文(简体) ), arr=([0]=x [1]=y)
  • 控制流量 : if/elif/else/fi, (中文(简体) ), while/until, (中文(简体) ), for/in, (中文(简体) ), select/in, (中文(简体) ), case/esac
  • 功能,子壳,块, [[ ]], (中文(简体) ), (( )), (中文(简体) ), coproc, (中文(简体) ), time, (中文(简体) ), !
  • 扩展缩略语 @(foo), (中文(简体) ), *(bar) (巴什/克什语)
  • 评论(与 keepComments: true(中文(简体) )

状态

工作正在进行中。 覆盖基于 AST 的命令分析所需的 Bash 子集(分类,可变- mutation tracking, guardrail reference). 它不是一个完整的POSIX/Bash parser;不太常见的方言特征中的边框可能缺失.

发展

要求数 无 对于 dev 外壳:

nix develop
pnpm install
pnpm test        # vitest
pnpm typecheck   # tsc --noEmit
pnpm lint        # biome
pnpm build       # rolldown + declarations

许可证

麻省理工学院——见 自由主义。此工程是 TypeScript 移植 mvdan/sh (英语) (BSD 3-Clause,丹尼尔·马蒂); 原始许可证包含在 自由主义。 。 。 .

版本与发布记录

@aliou/sh 共发布 11 个版本,首次发布于 2026/02/05;过去 12 个月发布了 11 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.4.0latest2026/11/05今天
0.3.42026/10/0630 天前
0.3.32026/09/201 个月前
0.3.22026/09/131 个月前
0.3.12026/09/052 个月前
0.3.02026/08/242 个月前

关于 @aliou/sh 的常见问题

@aliou/sh 是什么?

POSIX/Bash/mksh/zsh的外壳解析器/AST(WIP)

如何安装 @aliou/sh?

在项目目录运行 npm install @aliou/sh,或使用 pnpm add / yarn add / bun add。

@aliou/sh 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@aliou/sh 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@aliou/sh 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@aliou/sh 可以商用吗?

@aliou/sh 使用 MIT AND BSD-3-Clause 许可。声明的许可为 MIT AND BSD-3-Clause,请阅读许可原文确认使用条件。以上为概括,不构成法律意见,请以许可原文为准。

@aliou/sh 的下载量有多少?

根据 npm 官方下载统计,@aliou/sh 在 2026/10/06 – 2026/11/04 这 30 天内被下载 6,899 次,日均约 230 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@aliou/sh 还在维护吗?

最新版本 0.4.0 发布于 2026/11/05(今天);至今共发布 11 个版本,其中过去 12 个月发布了 11 个;首次发布于 2026/02/05。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。