使用 Tee 和 Paste 会导致死锁

使用 Tee 和 Paste 会导致死锁

我正在尝试使用 tee 将命令的标准输出重定向到两个“分支”以进行单独处理。最后,我需要使用粘贴合并两个“分支”的结果。我为生产者想出了以下代码:

mkfifo a.fifo b.fifo
python -c 'print(("0\t"+"1"*100+"\n")*10000)' > sample.txt
cat sample.txt | tee >(cut -f 1 > a.fifo) >(cut -f 2 > b.fifo) | awk '{printf "\r%lu", NR}'
# outputs ~200 lines instantly
# and then ~200 more once I read from pipes

然后在一个单独的终端中启动消费者:

paste a.fifo b.fifo | awk '{printf "\r%lu", NR}'
# outputs ~200 once producer is stopped with ctrl-C

问题是它挂起了。此行为似乎取决于输入长度:

  1. 如果输入行较小(即,如果第二列包含 30 个字符而不是 100 个),则可以正常工作。
  2. 如果a.fifob.fifo被输入相同(或长度相似)的输入,看起来它也可以正常工作。

a.fifo当我在 say 中喂短块而在 . 中喂长块时,问题似乎出现了b.fifo。此行为不取决于我在 中指定管道的顺序paste

我对 Linux 及其管道逻辑不是很熟悉,但似乎它不知何故陷入了僵局。我的问题是这是否可以以某种方式可靠地实现?如果是这样,怎么办?也许还有其他方法不使用teeand paste

答案1

我还没有详细理解这个问题。显然,这与填充某些缓冲区的每行的大小差异有关。

这可以通过扩大缓冲区来“解决”:

paste a.fifo <(buffer <b.fifo) | awk '{printf "\r%lu", NR}'

有趣的事实:buffer在生成命令中添加 a 可以让awk完成,但使用命令仍然会阻塞(在我的情况下接近结束):

$ cat sample.txt | tee >(cut -f 1 > a.fifo) >(cut -f 2 | buffer > b.fifo) | awk '{printf "\r%lu", NR}; END { print; print NR; }'
10001


$ paste a.fifo b.fifo | awk '{printf "\r%lu", NR}'
8152

恕我直言,没有意义。如果涉及到错误,我不会感到惊讶。

相关内容