CLI 参考
ash 的主要 CLI 是机器接口:成功输出和错误诊断都使用稳定的 ASON,不提供人类帮助页、
颜色或进度条。独立且受 feature 控制的 ash shell 入口明确面向人类,使用普通字节、
诊断与退出状态,而不是 ASON。
ash self replace 是更新流程使用的内部 Windows 辅助入口,不是普通 Harness API。
人类 Shell 检查点
当前人类 Shell 检查点会在 stdin 为终端时打开跨平台行编辑 REPL,并针对同一份持久原生状态
顺序执行当前命令与管道语法。已实现 pwd、echo(含 -n)、cd、展开后的
export/unset、set pipefail 控制、exit、可移植 ls、原始字节 cat、文本
grep、可移植 cp/mv/rm、只创建空文件的 touch、命名参数与上一状态展开、
嵌套命令替换、引用感知的路径名展开、宿主原生命令、Windows 上显式 WSL 命令,以及同一行
原生/WSL/可移植/状态管道、左结合的 &&/|| 条件列表,以及有序的原生、WSL、
可移植与状态重定向;源码也可以来自
-c SOURCE、原生
脚本文件路径或 stdin:
文件、stdin 与 Profile 源码必须是有效 UTF-8,且不能超过 1 MiB;原生文件路径本身
不会转换为 UTF-8。以 - 开头的文件参数可写成
ash shell -- ./-script.ash。可移植 ls 最多
接受一个路径(默认 .),按稳定原生顺序每行输出一个名称,并支持 -a/--all、
-d/--directory、-1、短选项组合与 --。可移植 cat 要求一个路径,原样输出
字节且不添加换行,接受 --,并共享 128 MiB 读取/捕获上限。在多阶段管道中,
cat - 会消费上游字节流;独立命令可通过显式 < 文件提供 -。未重定向的独立
stdin -、选项与多个文件仍会明确失败。
可移植 grep 要求一个有效 UTF-8 的普通文件,
默认使用 Rust 正则表达式;支持 -E/--extended-regexp、
-F/--fixed-strings、-i/--ignore-case、-n/--line-number、短选项组合与
--。搜索上限为 64 MiB;无匹配时不输出诊断并返回状态 1。在多阶段管道中,
grep PATTERN - 会用同一语义消费上游 UTF-8 流,输出上限为
128 MiB;独立命令也可通过 < 提供 -。目录、多个文件、未重定向的独立 stdin
- 与不支持的选项都会明确失败。
可移植 cp SOURCE DESTINATION、mv SOURCE DESTINATION、rm PATH 与
touch PATH 只接受这些精确普通文件参数数量和 --。持久 cwd 是它们的耐久事务
根。父路径穿越、逃逸、符号链接/reparse 穿越、目录、超过 128 MiB 的文件,以及无法
写入 UTF-8 日志的路径都会显式失败。复制、移动与 touch 都不覆盖;当前 touch 只
创建新的空文件,不更新已有文件时间戳。复制、移动和删除会在执行前立即派生 BLAKE3
源 preimage,再由与 ASH/1 fs 共用的事务重验。冲突不重试、返回状态 1,并保留外部
变化或已有目标。事务根下保留的 .ash 目录保存跨进程锁、回滚与重启恢复状态。
启动 Profile 是显式选择的:--profile FILE 指定一个文件,非空 ASH_PROFILE 提供
配置默认值,--no-profile 则禁用两者。相对路径以 Shell 初始 cwd 为基准。Profile
会在执行任何命令前完整解析,因此语法错误不会应用前缀;非交互调用在带源码位置的
诊断后以状态 2 停止,交互调用则输出同一诊断并以安全模式打开。Profile 中的 cd
和导出环境等状态会延续到所选输入。
提示符默认为 ash> ;ASH_PROMPT 可替换它,但必须是有效 UTF-8。在提示符处按
Ctrl+C 会把 $? 设为 130 并继续,EOF 则返回上一状态。exit [STATUS] 会停止当前
提交源码的剩余命令并退出 REPL;省略状态时复用 $?,显式值只能是 0 到 255 的
整数,非法参数返回 2 但不会退出。
ASH_HISTORY 选择相对初始 cwd 的持久历史文件,空值会禁用持久化。类 Unix 主机
默认依次使用 $XDG_STATE_HOME/ash/history 与
$HOME/.local/state/ash/history,Windows 使用
%LOCALAPPDATA%\ash\history。以空格或制表符开头的行不会记录。符号链接和非普通
文件目标会被拒绝,Unix 历史文件强制为 0600;路径不安全或不可用时会给出警告,
但内存中的行编辑会话仍可使用。
export NAME=VALUE 与 unset NAME 会持久更新 Shell 变量和导出环境。两者各接受一个
展开后的参数和 --;名称必须是 ASCII Shell 标识符,空值会被保留,移除不存在的
名称也会成功。可能含分隔符的值需要引用,例如 export COPY="$SOURCE"。列出环境与
多个名称尚未实现。
set -o pipefail 会持久启用“最右失败阶段”管道状态,set +o pipefail 恢复默认的
最终阶段策略;其他 set 形式返回状态 2。启动 Profile 可以预先选择策略。放入管道
时,set 只操作该阶段的状态克隆,不会修改父 Shell 策略。
$NAME、${NAME} 与 $? 会在每条命令解析执行目标前展开。Shell 变量优先于按宿主
规则查询的导出环境,未定义名称为空。单引号与转义后的美元符保持字面量;双引号保留
单个原生字段(包括空字段),未引用值则按固定 ASCII 空格、制表符与 LF 拆分,未引用
空展开可能移除整个词。当前检查点不使用 IFS 配置拆分;原生字符串单元会无损通过
展开和直接 argv 启动。
嵌套 $(SOURCE) 命令替换会解析为同一份类型化 Script 计划,诊断保留顶层源码的
精确位置,嵌套上限为 32 层。命令词与文件重定向目标中的替换统一按源码顺序执行。
每次替换都会获得完整 ShellState 克隆,因此 cwd、变量、环境、选项、状态与 exit
只在内部生效;普通外部进程与文件系统副作用仍然可见,即使后续管道阶段的外层预检
失败也不会回滚。ash 捕获 stdout 并删除全部尾随 LF;双引号内保留单个字段和内部
换行,未引用时才按固定 ASCII 分隔符拆分。
内部非零状态不会覆盖父 $? 或阻止外层命令,stderr 与诊断只向外传播并渲染一次。
输出中的 NUL 会被拒绝;Unix 保留非 UTF-8 原生字节,Windows 则要求有效 UTF-8。
替换值、stdout 与 stderr 共享剩余的 128 MiB 同步额度;捕获失败会阻止外层命令
执行。短路管道完全不执行替换,且整份源码仍会在所有副作用前完整解析。
固定的未引用字段拆分之后,路径名展开会在命令字段和重定向目标中识别活动的 *、
?、[abc]、升序 [a-z],以及取反的 [!abc]/[^abc]。单引号、双引号与
反斜杠会保护操作符;未引用的参数或命令替换输出可以引入模式。相对模式从持久 cwd
枚举,绝对模式保持绝对路径;匹配区分大小写,并按无损原生路径单元排序。只有组件以
字面量点开头时,通配符才会选择点文件;** 不递归。非法字符类或无匹配模式会在
启动命令前失败,重定向仍必须恰好得到一个路径。每条命令及其重定向共享 32,768 个
活动模式单元、65,536 个已检查目录项与 4,096 个匹配结果的上限。被短路的条件分支
不会读取目录。
原生程序通过持久 PATH 或显式 native: 前缀解析。ash 会把解析后的参数向量、当前
目录和导出环境直接交给解析出的宿主可执行文件,绝不插入宿主 Shell 命令字符串。
未重定向的独立子进程仍使用空 stdin 并同步捕获输出,因此自身需要前台终端的程序属于 H4 作业
控制,而不是当前行编辑 REPL。stdout 与 stderr 共享剩余的 128 MiB 捕获额度,普通
的非零原生退出状态会直接成为命令状态,不额外生成诊断。
在 Windows 上,linux:COMMAND 会显式选择 WSL。ash 首先解析 wsl.exe;launcher
缺失时返回状态 126 与解析诊断,普通命令解析失败也绝不会隐式转入 WSL。wrapper 会收到
可选发行版、通过 --cd 传入的当前 Windows cwd,以及 --exec 后彼此独立的 Linux
命令和每个参数;不会插入宿主或 Linux Shell 字符串。当前 CLI 使用用户的默认发行版,
嵌入方可以通过 ShellOptions 显式选择;命令状态会保留 WSL backend 与所选发行版。
原生、WSL 与可移植命令以及已实现的状态 builtin 支持 <、>、>>、2>、
2>>、2>&1 与 1>&2,并从左到右应用:
command >out 2>&1 会把两路流合入 out,而 command 2>&1 >out 会让 stderr 保留在
原 stdout 捕获上。每个文件目标(包括 $(...) 与路径名模式)最终必须恰好得到一个
原生字段;相对
路径以持久 cwd 为基准。
文件直接连接子进程或父任务 OS 句柄,因此重定向输出不占同步捕获额度;一份经过
校验的图级顺序会按阶段与重定向源码顺序交错打开原生、可移植和状态任务文件,被后续赋值覆盖的
目标仍会打开。目标缺失、歧义或无法打开时返回状态 1 和重定向诊断。带源码位置的
Shell 诊断仍写入 Shell stderr,而不是命令原始 stderr。状态与可移植修改命令的参数、
目标都会在打开文件前完成预检;简单状态命令先打开文件再修改父状态,打开失败会阻止
状态修改、可移植文件事务或 exit
请求。WSL 重定向文件由 Windows 宿主按同一顺序打开,并直接连接 wrapper 标准句柄。
同一行的 | 可组成两个到 32 个阶段的管道。每个阶段可以是宿主原生命令,也可以是
Windows 上显式选择的 WSL 命令、可移植 pwd、echo、ls、cat 或 grep,也可以是
可移植 cp、mv、rm、touch,也可以是已实现的状态 cd、export、unset、
set 或 exit;别名、函数与尚未实现的状态命令
会在完整预检时拒绝。相邻原生或 WSL wrapper 阶段仍由 OS 管道直连。涉及进程内阶段的边界只保留显式声明的父进程
异步端点,并将有界任务与原生执行、捕获并发轮询,因此无需完整物化
原生流或可移植 cat/grep 流,且保留 OS 背压。只有 cat - 与
grep PATTERN - 消费上游 stdin;其他可移植形式
会关闭该 reader,使上游 producer 能观察 broken-pipe 失败。最终进程内输出、最终原生
输出与捕获的原生 stderr 共享剩余的 128 MiB 额度。状态默认取最后阶段;启用
set -o pipefail 后改取最右侧失败的原生、WSL、可移植或状态阶段(含 128 + signal),
全成功时仍取最后阶段。
状态阶段不消费 stdin,在独立的 ShellState 克隆上执行,并在完成时关闭空 stdout。
父 Shell 的 cwd、变量、环境、选项与退出请求都不会改变;下游 reader 收到 EOF,管道
中的 exit 也只贡献普通阶段状态。
修改阶段同样关闭 stdin、不输出 stdout,并把事务冲突或文件系统状态交给最终阶段/
pipefail 选择;其重定向文件会按图级顺序先于事务打开。
任意原生、WSL、可移植或已实现状态阶段都可以重定向 stdin、stdout 或 stderr,描述符复制仍按源码顺序应用。若
producer 不再引用内部管道,ash 会关闭父进程 writer,使下游 reader 收到 EOF;若
consumer 用文件替换管道 stdin,ash 会关闭父进程 reader,使上游 writer 遇到原生
broken-pipe 行为,随后仍由最终阶段或 pipefail 策略决定可见状态。即使原描述符随后
被重定向,只要复制出的描述符仍引用管道,该连接就会保留。状态文件会加入同一全局
打开顺序;这些 builtin 不产生命令原始输出,重定向其空 stdout 会正常关闭下游。
WSL 阶段复用同一份经过校验的管道与文件图,不增加 relay 缓冲。
父进程管道与文件句柄领取完毕后,ash 会把原生图转换成统一作业监督器。原生退出结果
保持规格顺序;任一准备、捕获或等待失败都会在管道返回前终止并回收所有原生成员拥有
的进程树。可移植/状态 future 与捕获 drain 完成后,监督器才进入不会被中途取消的有序
等待;两阶段共用同一完成边界。
&& 与 || 以相同优先级连接完整管道,并从左到右求值。&& 只在上一可见状态为
0 时执行下一管道,|| 只在其非零时执行;输入状态已经过最终阶段或 pipefail
选择。被短路的分支会为下一链接与 $? 保留该状态,不输出诊断,也不进行参数展开、
命令解析、参数预检、重定向打开、进程启动、状态修改或可移植文件事务。只有实际执行的
exit 才会停止源码。整份提交源码仍在任何副作用前完整解析,因此被跳过分支中的语法
错误也会阻止全部前缀命令。操作符后可用空白、注释与换行在同一源码中续写;未连接的
换行或 ; 会开始新的无条件列表。
剩余命令语言(包括别名、函数与 subshell 状态)、
终端流式输出、前台交互程序与作业控制,以及 WSL 已安装发行版探测、backend
策略/配置、通用参数路径映射、环境转发、
Linux 侧所有权与中断归一化尚未实现。
常规二进制启用 human-shell feature;
cargo build -p a3s-ash --no-default-features 保留最小机器专用构建。
错误契约
示例:
对机器命令而言,退出码按错误类别稳定映射。调用方应根据 ASON 诊断字段和退出码分支,
不应匹配本地化文本;无参数或未知机器命令返回 Usage 类错误,而不是打印帮助。
ash shell 则有意输出人类诊断和常规命令状态。
运行目录
文件操作受启动时工作区约束。路径必须使用规范逻辑形式,拒绝词法逃逸、符号链接或
Windows reparse point 绕过。exec 也不会自动切换到隐式系统 Shell。
人类 Shell 状态改用原生 PathBuf 与 OsString。cd、export、unset、ls、
cat 与 grep 继承普通用户权限。可移植 cp、mv、rm、touch 则有意把当前
cwd 绑定为带日志的工作区,不能向上穿越。原生外部程序继承相同的 cwd/环境状态和普通
OS 权限。原生路径和环境单元会被保留或可逆转义;这不会削弱或替代 ASH/1 的工作区约束。