【发布时间】:2018-07-10 03:30:28
【问题描述】:
我有一个以空值分隔的流,其中包含未知数量的部分。对于每个分隔的部分,我想将其通过管道传输到另一个管道,直到最后一个部分被读取,然后终止。 在实践中,每个部分都非常大(~1GB),所以我想在不将每个部分读入内存的情况下这样做。
例如,假设我有由以下人员创建的流:
for I in {3..5}; do seq $I; echo -ne '\0';
done
我会得到一个看起来像这样的蒸汽:
1
2
3
^@1
2
3
4
^@1
2
3
4
5
^@
当通过cat -v 传输时。
我想通过paste -sd+ | bc 管道传输每个部分,所以我得到一个看起来像这样的流:
6
10
15
这只是一个例子。实际上流更大,流水线更复杂,所以不依赖流的解决方案是不可行的。
我尝试过类似的方法:
set -eo pipefail
while head -zn1 | head -c-1 | ifne -n false | paste -sd+ | bc; do :; done
但我只得到
6
10
如果我离开 bc 我会得到
1+2+3
1+2+3+4
1+2+3+4+5
这基本上是正确的。这让我相信这个问题可能与缓冲以及每个进程实际上与它们之间的管道交互的方式有关。
有没有办法修复这些命令交换流的方式,以便我可以获得所需的输出?或者,有没有办法通过其他方式来实现?
原则上,这与this question 有关,我当然可以编写一个程序,将标准输入读入缓冲区,查找空字符,并将输出通过管道传输到衍生的子进程,正如接受的答案对那个问题所做的那样.鉴于 bash 中对流和空分隔符的普遍支持,我希望做一些更“原生”的事情。特别是,如果我想走这条路,我将不得不在字符串中转义管道 (paste -sd+ | bc),而不是让同一个 shell 解释它。这本身并没有什么不好的地方,但它有点难看,并且需要一些容易出错的转义。
编辑
正如答案中所指出的,head 不保证它缓冲了多少。除非它一次只缓冲一个字节,这是不切实际的,否则这永远不会奏效。因此,似乎唯一的解决方案是将其读入内存或write a specific program。
【问题讨论】:
-
xargs -0 -n 1在这里有用吗? -
你真的需要
bc吗?如果你只是使用整数,为什么不坚持使用原生 shell 数学呢? -
顺便说一句,回复:
set -e,请参阅BashFAQ #105——如果赶时间,请跳过以下练习的寓言。它的行为经常非常不直观(和wildly incompatible between different shells),以至于可以说它弊大于利。 -
@MarkPlotnick 就我对 xargs 手册的阅读而言,它将读取空分隔字符串并将它们传递给命令调用。这不起作用有两个原因,a) 它将它读入内存,b) 如果它填充了当前 shell 的最大命令长度,它将失败。
-
@CharlesDuffy
paste -sd+ | bc只是为了说明一个示例管道。实际情况并非如此。
标签: bash stream pipe delimiter pipeline