Command 看起来很简单,实际有不少陷阱:参数会不会被 shell 解释?退出码与信号怎么区分?管道读法不对为什么死锁?子进程什么时候变僵尸?这篇每个问题都跑一个真实的子进程来回答。
编译:成功
运行(退出码 0):
echo 输出 "hello a; echo INJECTED $HOME\n" 状态 Some(0) 成功 true
(参数里的 ; 和 $HOME 原样当作字符,没有被 shell 解释,也就没有 INJECTED 这个独立命令)
sh -c:stdout "out\n" stderr "err\n" 退出码 Some(3) 成功 false 编译:成功
运行(退出码 0):
不存在的命令:kind = NotFound,os_error = Some(2)
没有执行权限的文件:kind = PermissionDenied,os_error = Some(13)
子进程被 SIGTERM 终止:code() = None,signal() = Some(15),success() = false
Display:signal: 15 (SIGTERM) 编译:成功
运行(退出码 0):
sort -r 的输出:"cherry\nbanana\napple\n"
管道 printf | wc -l:"3" 编译:成功
运行(退出码 0):
500 ms 后:读 stdout 的线程完成了吗? false(子进程卡在写 stderr,没有机会写 stdout 或退出)
现在读 stderr,读到 200000 字节(用时 2 ms),死锁解除
stdout 线程结果:"done"
对照:output() 内部同时读两个管道,不会死锁:stdout "done",stderr 200000 字节死锁是 macOS 上的实测现象;管道缓冲区的具体大小没有测量。
编译:成功
运行(退出码 0):
继承环境 + env + current_dir:MY=from-rust HOME_SET=yes PWD=tmp
env_clear 之后只剩手动设置的:MY=only HOME_SET=
env_remove("HOME"):HOME_SET=环境变量读取见环境变量读取。
编译:成功
运行(退出码 0):
子进程 true 已经退出,父进程没有 wait,ps 状态:"Z"(Z = 僵尸)
drop(Child) 之后状态:"Z"(drop 不会 wait)
调用 wait() 之后:退出状态 Some(0),ps 状态 ""(已被回收,不再存在)