cas*_*sey 36
如果true
退出,该管的读取端是封闭的,而是yes
继续尝试写入到写边。这种情况称为“管道损坏”,它会导致内核向 发送SIGPIPE
信号yes
。由于yes
对这个信号没有什么特别的,它会被杀死。如果它忽略该信号,它的write
调用将失败并显示错误代码EPIPE
。这样做的程序必须准备好注意到EPIPE
并停止编写,否则它们将进入无限循环。
如果您执行strace yes | true
1,您可以看到内核为两种可能性做准备:
write(1, "y\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\n"..., 4096) = -1 EPIPE (Broken pipe)
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=17556, si_uid=1000} ---
+++ killed by SIGPIPE +++
Run Code Online (Sandbox Code Playgroud)
strace
正在通过调试器 API 观察事件,它首先告诉它系统调用返回错误,然后告诉它信号。yes
但是,从的角度来看,信号首先发生。(从技术上讲,信号是在内核将控制权返回给用户空间之后传递的,但在执行任何更多机器指令之前,因此write
C 库中的“包装器”函数没有机会设置errno
并返回到应用程序。)
1遗憾的是,这strace
是 Linux 特有的。大多数现代 Unix 都有一些执行类似操作的命令,但它通常具有不同的名称,它可能不会彻底解码系统调用参数,有时它仅适用于 root。
有没有贝壳?true 会永远循环吗?
不太可能,因为yes
命令正在使用管道,当管道损坏时它会失败。sleep
另一方面,不使用管道,所以:
sleep 100000000 | true
Run Code Online (Sandbox Code Playgroud)
至少会运行 100000000 秒。