在Bash脚本中拆分并重新组合stdin

在Bash脚本中拆分并重新组合stdin,bash,redirect,stream,pipe,tee,Bash,Redirect,Stream,Pipe,Tee,假设我的Bash脚本中有流式文本数据,每行一条记录,我想在每行附加该行的一些函数,并将其输出到stdout: record1 record1 fn(record1) record2 -> record2 fn(record2) ... ... 这将是相对容易做到的,比如说,Awk。但是,假设我应用于输入数据的函数如果应用于流数据,效率会高出几个数量级(我有很多这样的函数,所以行方式Awk处理肯定不是一个选项)。这就是我提出的解决方案: input="$

假设我的Bash脚本中有流式文本数据,每行一条记录,我想在每行附加该行的一些函数,并将其输出到
stdout

record1      record1  fn(record1)
record2  ->  record2  fn(record2)
...          ...
这将是相对容易做到的,比如说,Awk。但是,假设我应用于输入数据的函数如果应用于流数据,效率会高出几个数量级(我有很多这样的函数,所以行方式Awk处理肯定不是一个选项)。这就是我提出的解决方案:

input="$(mktemp)"
trap "rm -rf ${input}" EXIT
cat > "${input}"
paste "${input}" <(some_function "${input}")
input=“$(mktemp)”
陷阱“rm-rf${input}”退出
cat>“${input}”
粘贴“${input}”简单(?)解决方案
最简单的解决方案可能是修改函数,使其输入总是在实际输出之前打印。数学上:将
f(x)=y
替换为
g(x)=“xf(x)”

如果无法轻松修改函数,请使用以下方法之一

无文件方法 如果您有足够的内存,您可以通过将stdin保存到一个变量来修改当前方法,使其在没有文件的情况下工作:

input="$(cat)"
paste - <(yourFunction <<< "$input") <<< "$input"
第一部分打印stdin,然后是通过函数管道传输的stdin。基本上与打印的
cat文件(f)
相同(编辑:订单上没有保证。请参见上面的注释。)

Lorem Ipsum
多好的二线啊
\t\r\n[]()*+\
#1
#2
#3
pr
会将该输出转换为

Lorem Ipsum#1
多好的第二线啊
\t\r\n[]()。?+\\35; 3

在每个
#
之前,都有一个制表器作为列分隔符。

这并没有消除对临时文件的需要,但它至少摆脱了
cat
的无用使用:

input="$(mktemp)"
trap "rm -rf ${input}" EXIT
tee "${input}" | paste - <(some_function "${input}")
input=“$(mktemp)”
陷阱“rm-rf${input}”退出

tee“${input}”| paste-
fn(recordX)
是使用
recordX
调用
fn
的结果,即使您可以从stdin中一次读取多行,但您希望每个记录写入输出(每行唯一),对吗?在这种情况下,一定需要一次处理一行?从这个意义上说,你不认为是的,但我的观点是,如果应用于整个流,而不是逐行调用,那么我上面提到的
某些函数
要快得多。为了使这更具体:
一些函数
这里是从输入中提取一个字段,然后对其进行base64解码,然后根据一些标准对其进行分类。如果是逐行运行,base64解码步骤是瓶颈;通过一些技巧,它可以在流式数据上运行以获得相同的结果,并且它可以在几分钟内而不是几小时/天内运行。。。我上面的解决方案非常有效,我只是想知道是否有更好/更好的方法。是的,在读端完全同意你的观点,但关键是你的写逻辑每行都是唯一的,对吗?您不能在每个唯一的行上进行批量写入吗?有道理吗?是的,有道理。我的解决方案计算
fn(record1)
fn(recordN)
的值,然后
paste
将它们放回一起。POSIX流/缓冲的本质使它们保持同步,这实际上是一种“批量写入”,但我看不出这一点与我的问题有什么关联。注意,虽然这是可行的,但它不适用于大型数据集。当达到管道缓冲区大小时,它似乎会失败,因此
cat
就是这样。
f() { awk '{print "#" NR}'; }
input="$(mktemp)"
trap "rm -rf ${input}" EXIT
tee "${input}" | paste - <(some_function "${input}")