fish shell与bash处理命名管道的差异:nc使用fifo时为何表现不同?
fish与bash处理命名管道的行为差异底层原因
核心背景:命名管道(FIFO)的默认特性
- 命名管道的
open系统调用默认是阻塞模式:如果以只读模式打开FIFO,调用会阻塞直到有其他进程以写模式打开同一个FIFO;反过来以只写模式打开也会阻塞直到有读端存在,只有读写两端同时就绪,open才会返回成功。
bash的执行逻辑
bash处理管道链时,会并行启动管道中的所有子进程,不会等待前一个进程的初始化/重定向操作完成。
你执行nc -vv -l -k -p 8001 <answer | tee -a answer时,bash会同时启动nc和tee两个进程:
nc进程发起只读打开answer的系统调用- 几乎同时
tee进程发起追加写打开answer的系统调用
读写两端同时就绪,两个open调用直接返回成功,nc正常启动监听,不会出现阻塞。
fish的执行逻辑
fish为了保证错误处理的一致性,采用了完全不同的执行顺序:先完成前一个命令的所有重定向操作,确认没有错误后,才会启动管道链后面的命令。
同样执行上述命令时,fish的执行步骤是:
- 先处理
nc命令的输入重定向,发起只读打开answer的系统调用 - 此时
tee进程还没有启动,没有写端打开answer,所以open调用直接进入阻塞状态,整个命令看起来就挂住了
- 你手动执行
echo "" > answer时,相当于有了临时的写端,阻塞的open调用返回成功,nc启动后才会接着启动tee进程,后续流程就正常了 - 你按下Ctrl+C终止进程时,打断的正是阻塞状态的
open系统调用,所以fish会返回open: Interrupted system call的报错。
内容的提问来源于stack exchange,提问作者Momh
相关产品推荐
相关产品推荐

