0

我试图在 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 -)) >(ts '[%Y-%m-%d %H:%M:%S]' >(echo))就此而言),首先将其解决为一个完整且独立的命令。因此split( 和echo) 正在接收一个空输出,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接收然后输出命令输出)。我想我只是非常误解流程替换在这一点上是如何工作的

4

3 回答 3

1

如果你真的想让一个命令将 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 -))

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

于 2021-03-10T15:56:50.550 回答
1

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

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

这将输出发送cmd到第一个管道,而错误流从cmd进入第二个管道。引入文件描述符 3 是为了将错误流与错误流ts隔离split开来,但这可能是不可取的。引入 fd 4 是为了防止输出split被第二个管道消耗,这可能是不必要的(split例如,如果不产生任何输出。)

于 2021-03-10T16:28:50.307 回答
0

这:

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

扩展由命令行上的进程替换生成的文件名ts,因此运行的内容类似于ts '[%Y-%m-%d %H:%M:%S]' /dev/fd/63. ts然后尝试打开fd那个去split从那里读取输入,而不是从原始标准输入读取。

这可能不是你想要的,在我的机器上,我得到了一些副本,tssplit在测试时卡在了后台。可能已成功相互连接,这可能解释了缺少错误消息的原因。

你可能打算写

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

重定向到进程替换。

也就是说,您可以在ts和之间使用管道split

于 2021-03-10T17:59:36.073 回答