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

5
在 fish shell 中执行这些命令时
$ mkfifo answer
$ nc -vv -l -k -p 8001 <answer | tee -a answer

命令挂起。 如果我通过“echo "" > 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中有什么不同的情况可以解释这种不同的行为?

2
除了 ridiculousfish 的答案之外,我要指出你实际上不能依赖于 Bash 或任何其他 POSIX shell 的行为。打开一个 FIFO 进行读取将会阻塞,直到有一个进程打开它进行写入。在 bash 中,<answer 打开是阻塞的,但对你来说并不明显,因为它发生在一个子进程中。 - Kurtis Rader
1个回答

11

关键区别在于,fish 在父 shell 中的 fork 之前打开重定向文件,而 bash 则是在子进程中的 fork 之后。

当你为读取打开一个命名管道时,该调用会阻塞直到有相应的写入者(反之亦然)。你的管道包含读取器和写入器,但要求相应的打开调用在子进程中并行执行。在 fish 中,nc 必须等到文件打开才能启动,因此会出现死锁现象。

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

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

鱼的行为是这样的,因为它也使用线程,这限制了你在分叉的子进程中所能做的事情。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接