我正在尝试使用 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
问题是它挂起了。此行为似乎取决于输入长度:
- 如果输入行较小(即,如果第二列包含 30 个字符而不是 100 个),则可以正常工作。
- 如果
a.fifo
和b.fifo
被输入相同(或长度相似)的输入,看起来它也可以正常工作。
a.fifo
当我在 say 中喂短块而在 . 中喂长块时,问题似乎出现了b.fifo
。此行为不取决于我在 中指定管道的顺序paste
。
我对 Linux 及其管道逻辑不是很熟悉,但似乎它不知何故陷入了僵局。我的问题是这是否可以以某种方式可靠地实现?如果是这样,怎么办?也许还有其他方法不使用tee
and 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
恕我直言,没有意义。如果涉及到错误,我不会感到惊讶。