# 操作系统 `os/` 命名空间涵盖进程标识与环境、子进程执行和 OS 信号处理。它被编译 进每个运行时,无需导入。命令既可以带显式参数向量直接运行(`os/run`、 `os/status`、`os/lines`),也可以通过 `/bin/sh -c` 运行(`os/shell`); 两种形式都捕获 stdout 和 stderr 并报告状态。沙箱会话可能被拒绝子进程 或网络访问 —— 参见 Sandbox。 ## 函数 ### 进程与环境 | 函数 | 用途 | |---|---| | `os/args` | 命令行参数,字符串向量;`argv[0]` 是脚本路径 | | `os/cwd` | 当前工作目录 | | `os/chdir "path"` | 更改进程工作目录;返回 `nil`,失败时返回 `%Err` | | `os/env "NAME"` | 环境变量值(字符串),未设置时为 `nil` | | `os/pid` | 当前进程 id | | `os/cpu-count` | 逻辑 CPU 数量(至少 1);用于确定工作进程池大小 | | `os/exit ?code` | 以退出码终止(`0`–`255`,默认 `0`);永不返回 | ### 子进程 | 函数 | 用途 | |---|---| | `os/run cmd args...` | 直接运行命令并捕获其结果映射 | | `os/run-async cmd args...` | 在线程外运行同一命令;返回结果映射的 Future | | `os/shell "command string"` | 通过 `/bin/sh -c` 运行字符串 —— 管道、重定向、通配 | | `os/status cmd args...` | 运行命令;返回结果映射(见说明) | | `os/lines cmd args...` | 运行命令并返回按行拆分的 stdout 向量 | ### 信号 | 函数 | 用途 | |---|---| | `os/on-signal $signal $handler` | 为信号注册处理闭包;`true` 或 `%Err` | | `os/off-signal $signal` | 移除某信号的所有处理函数;返回移除的数量 | | `os/signals` | 可捕获信号关键字的向量 | | `os/kill $pid $signal` | 按名称向进程 id 发送信号;`true` 或 `%Err` | 说明: - 每次子进程调用都会产生形如 `%{ :status N :stdout "..." :stderr "..." }` 的结果映射。输出会被捕获(每流最多 10 MiB),末尾换行符会被去除。 `:status` 是退出码;被信号终止的子进程映射为 `128`,被停止的映射为 `127`。 - `os/run`、`os/status` 和 `os/lines` 直接接受可执行文件及其参数 —— 不经 shell 解释。需要管道时使用 `os/shell`,或使用 `[|cmd]` 语法, 后者是同一事物的便捷形式,仅返回 stdout(非零退出时返回 `%Err`)。 非字符串参数会格式化为命令行;最多使用 64 个参数。 - `os/run-async` 在 Future 背后解析为同一个 `%{ :status :stdout :stderr }` 映射:`[await [os/run-async ...]]`。 可执行文件缺失或派生失败会解析为 `%Err{:message}`;命令名缺失或 执行器失败会立即返回 `%Err`(而不是以 Future 形式)。挂起的命令会 占住一个池线程,因此简单的阻塞用途请优先使用 `os/run`。 - `os/status` 返回与 `os/run` 相同的 `%{ :status :stdout :stderr }` 映射;只需要退出码时读取 `$res~status`。 - 可捕获的信号包括 `:sigint`、`:sigterm`、`:sighup`、`:sigquit`、 `:sigusr1`、`:sigusr2` 和 `:sigalrm`。名称可以是关键字或字符串, 大小写不敏感,并可选带 `sig` 前缀(`:sigusr1`、`"USR1"`、`:usr1`)。 `sigkill` 和 `sigstop` 仅用于发送 —— 内核从不会将它们递送给处理函数。 - 处理函数仅在事件循环泵送时触发(`vwait`、`update`、REPL、服务器)。 注册信号会拦截它,因此存在处理函数时 Ctrl-C 不再终止进程。处理函数 接收 `%{ :type :signal :signal :code :pid :uid }`;`:pid`/`:uid` 标识 发送者。使用 `os/off-signal` 解除信号阻塞并恢复其默认处置。已注册的 处理函数会让 `vwait` 保持存活,因此“一直运行直到收到信号”是自然形态。 ## 示例 ### 运行命令并检视结果
set res [os/run "uname" "-s"]
echo "status:" $res~status
echo "stdout:" $res~stdout
if ($res~status != 0) {
    echo "stderr:" $res~stderr
}
### Shell 管道与行输出
set res [os/shell "ps aux | grep deft | wc -l"]
echo "deft processes:" $res~stdout

each [os/lines "printf" "a\nb\nc"] {|line| echo "got:" $line }
### 线程外执行
def fut [os/run-async "sh" "-c" "echo out; echo err >&2"]
set res [await $fut]
# %{ :status 0 :stdout "out" :stderr "err" }
### 信号处理
[os/on-signal :sigusr1 {|ev|
    echo "got" $ev~signal "from pid" $ev~pid
}]
[os/kill [os/pid] :sigusr1]     # self-send for testing
[update]                        # pump the event loop once -> handler fires
echo "removed:" [os/off-signal :sigusr1]
### 环境与参数
echo "cwd:" [os/cwd] "pid:" [os/pid] "cpus:" [os/cpu-count]

set home [os/env "HOME"]
if [nil? $home] { echo "HOME is not set" }

each [os/args] {|arg| echo $arg }
## 另见 - I/O —— 通道与裸 `open` / `puts` / `gets` / `close` 动词 - Sandbox —— 对子进程和网络的 Landlock 限制 - Tasks —— `await` 与 Future 消费动词 - 文件系统 —— `fs/*` 文件与路径辅助函数