# 操作系统
`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 }