如何解决Bash 多进程替换重定向命令
我试图在 BASH 命令中使用多个进程替换,但我似乎误解了它们解析和重定向到彼此的顺序。
系统
Ubuntu 18.04
BASH 版本 - GNU bash,版本 4.4.20(1)-release (x86_64-pc-linux-gnu)
问题
我正在尝试将命令的输出重定向到 tee
,将其重定向到 ts
(添加时间戳),然后将该重定向到 split
(将输出拆分为单独的文件)。我可以让输出重定向到 tee
和 ts
,但是在重定向到 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 -))
- 这会打印带有时间戳的命令(如 tee
和 ts
应该),此外还会创建带有命令输出的 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
接收然后输出命令输出)。我想我只是非常误解了流程替换在这一点上是如何工作的
解决方法
如果你真的想让一个命令将 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 仅在提示打印后才打印。可能有一种方法可以通过复制文件描述符来避免这种情况,但这是我能想到的最好的方法。
,如果需要,您可以将命令中的错误流发送到与输出不同的管道中:
{ { cmd 2>&3 | ts ... | split; } 3>&1 >&4 | ts ... | split; } 4>&1
这会将 cmd
的输出发送到第一个管道,而来自 cmd
的错误流进入第二个管道。引入文件描述符 3 是为了将 ts
和 split
的错误流分开,但这可能是不可取的。引入 fd 4 是为了防止 split
的输出被第二个管道消耗,这可能是不必要的(例如,如果 split
不产生任何输出。)
这个:
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
以从那里读取输入,而不是从原始标准输入读取。
这可能不是您想要的,在我的机器上,我在测试时在后台获得了一些 ts
和 split
的副本。可能已经成功连接到对方,这可以解释为什么没有错误信息。
你可能打算写
ts '[%Y-%m-%d %H:%M:%S]' > >(split -d -b 10 -)
^
重定向到进程替换。
也就是说,您可以在 ts
和 split
之间使用管道。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。