处理命名管道时,fish shell 和 bash 有啥区别?

Posted

技术标签:

【中文标题】处理命名管道时,fish shell 和 bash 有啥区别?【英文标题】:What are the differences between fish shell and bash when handling named pipes?处理命名管道时,fish shell 和 bash 有什么区别? 【发布时间】:2021-09-17 01:49:41 【问题描述】:

在fish shell中执行这些命令时

$ mkfifo answer
$ nc -vv -l -k -p 8001 <answer | tee -a answer

命令挂起。 如果我通过echo "" &gt; answer 写信给answer。然后nc 恢复并开始正确收听。 如果,相反我CTRL-C挂了进程,下面是留言:

^C<W> fish: An error occurred while redirecting file 'answer'
open: Interrupted system call

另一方面,在 bash 中,执行时:

$ mkfifo answer
$ nc -vv -l -k -p 8001 <answer | tee -a answer
Listening on localhost 8001

命令挂起并直接开始收听。

fish 和 bash 中发生了什么不同的情况来解释这种不同的行为?

【问题讨论】:

除了荒谬的回答之外,我还要指出您实际上不能依赖 bash 行为;或任何其他 POSIX shell AFAICT。打开 FIFO 进行读取将阻塞,直到进程打开它进行写入。 &lt;answer 在 bash 中打开块,但对您来说并不明显,因为它发生在子进程中。 【参考方案1】:

主要区别在于fish在父shell中在fork之前打开重定向文件,而bash在子进程中在fork之后打开重定向文件。

当您打开命名管道进行读取时,打开调用将阻塞,直到有相应的写入器(反之亦然)。您的管道同时包含读取器和写入器,但要求相应的打开调用在子进程中并行发生。在鱼中nc 在文件打开之前无法启动,因此会出现死锁。

一种解决方法是安排子进程自行打开文件,而不是使用重定向。例如,这将避免死锁:

cat answer | nc -vv -k -l -p 8001  | tee -a answer

fish 之所以如此,是因为它也使用线程,这限制了您可以在分叉子项中执行的操作。

【讨论】:

以上是关于处理命名管道时,fish shell 和 bash 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

在 bash 中打开命名管道,而不读取或写入它

Fish Shell使用心得

命名管道不会等到在 bash 中完成

让 fish shell 与 gcloud 命令行工具一起工作?

如何通过 Shell (BASH/ZSH/SH) 获取文件的绝对路径?

Bash 重定向:命名管道和 EOF