BASH多进程替换重定向顺序

zvokhttg  于 2022-10-23  发布在  Linux
关注(0)|答案(3)|浏览(152)

我试图在Bash命令中使用多个进程替换,但我似乎误解了它们相互解析和重定向的顺序。

系统

Ubuntu 18.04
Bash版本-GNU bash,版本4.4.20(1)-Release(x86_64-PC-Linux-GNU)

问题所在

我正在尝试将命令的输出重定向到tee,将其重定向到ts(添加时间戳),然后将其重定向到split(将输出拆分成单独的文件)。我可以让输出重定向到teets,但在重定向到split时遇到了问题。

我的尝试

command >(tee -a >(ts '[%Y-%m-%d %H:%M:%S]' > tempfile.txt))-这会将输出重定向到tee的进程替换,然后重定向到进程替换ts,并添加时间戳,然后重定向到tempfile.txt这是我所期望的
command >(tee -a >(ts '[%Y-%m-%d %H:%M:%S]' >(split -d -b 10 -)))-这没有任何作用,即使我希望结果会是一堆在不同行上带有时间戳的10字节文件。
为了继续测试,我尝试使用echo,而不是查看command >(tee -a >(ts '[%Y-%m-%d %H:%M:%S]' >(echo)))会发生什么情况--打印来自初始tee的打印(理应如此),但echo打印一个空行,这显然与我得到的新结果无关-请参见底部的编辑
command >(tee -a >(ts '[%Y-%m-%d %H:%M:%S]') >(split -d -b 10 -))-这会打印带有时间戳的命令(就像teets应该的那样),此外还会创建带有命令输出的10个字节的文件(没有时间戳)。-这是我所期望的,也是有意义的,因为TEE被分别重定向到两个进程替换,这主要是一次理智的检查

我认为正在发生的事情

据我所知,>(ts '[%Y-%m-%d %H:%M:%S]' >(split -d -b 10 -))首先作为一个完整的、独立的命令进行解析。因此,split(和echo)正在接收来自ts的空输出,而ts本身没有输出。只有在此之后,实际命令才会解析并将其输出发送到其替换tee
这不能解释为什么command >(tee -a >(ts '[%Y-%m-%d %H:%M:%S]' > tempfile.txt))可以工作,因为根据这个理论,tee本身没有输出,所以ts应该接收而不是输入,并且还应该输出空白。
所有这些都是说,我真的不确定正在发生什么。

我想要什么

基本上,我只是想了解如何让command >(tee -a >(ts '[%Y-%m-%d %H:%M:%S]' >(split -d -b 10 -)))以它看起来应该的方式工作。我需要命令输出将自身发送到进程替代tee,它将把它发送到进程替代ts,并添加时间戳,这将把它发送到split,并将输出拆分成几个小文件。
我尝试了command > >(echo),但看到输出为空,这与我预期的不同(我希望echo接收并输出命令输出)。我想我只是在很大程度上误解了进程替换在这一点上是如何工作的。

dxxyhpgq

dxxyhpgq1#

如果需要,您可以将命令中的错误流发送到与输出不同的管道中:

{ { cmd 2>&3 | ts ... | split; } 3>&1 >&4 | ts ... | split; } 4>&1

这会将cmd的输出发送到第一个管道,而来自cmd的错误流则进入第二个管道。引入文件描述符3是为了将来自tssplit的错误流分开,但这可能并不可取。引入fd4是为了防止split的输出被第二个流水线消耗,这可能是不必要的(例如,如果split不产生任何输出)。

kqhtkvqz

kqhtkvqz2#

如果您真的想让一个命令将stdin/stderr重定向到单独的ts|tee|split,您可以做的一件事是

command 1> >(ts '[%Y-%m-%d %H:%M:%S]' | tee -a >(split -d -b 10 -)) 2> >(ts '[%Y-%m-%d %H:%M:%S]' | tee -a >(split -d -b 10 -))

但缺点是,只有在打印提示符之后才会打印T恤。可能有一种方法可以通过复制文件描述符来避免这种情况,但这是我能想到的最好的方法。

pdkcd3nj

pdkcd3nj3#

这一点:

ts '[%Y-%m-%d %H:%M:%S]' >(split -d -b 10 -)

ts的命令行上展开由进程替换生成的文件名,因此运行的内容类似于ts '[%Y-%m-%d %H:%M:%S]' /dev/fd/63。然后,ts尝试打开转到splitfd,以从那里读取输入,而不是从原始标准输入读取。
这可能不是您想要的,在我的机器上,我在测试时有一些tssplit的副本卡在后台。可能彼此成功连接,这可能解释了没有错误消息的原因。
你可能是想写

ts '[%Y-%m-%d %H:%M:%S]' > >(split -d -b 10 -)
                         ^

并重定向到进程替换。
也就是说,您只需在tssplit之间使用管道即可。

相关问题