Bash 多进程替换重定向命令
Bash Multiple Process Substitution Redirect Order
我试图在 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 字节文件(上面没有时间戳) . - 这是我所期望的并且是有意义的,因为 T 恤分别重定向到两个进程替换,这主要是一个完整性检查
我认为正在发生的事情
据我所知,>(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
,进程替换 tee
将其发送到进程替换 ts
并添加将其发送到 split
的时间戳并将输出拆分为多个小文件。
感谢您抽出宝贵时间以及您可能提供的任何帮助。
*Edit - 我刚刚尝试 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
然后尝试打开进入 split
的 fd
以从那里读取输入,而不是从原始标准输入读取。
这可能不是你想要的,在我的机器上,我在测试时得到了一些 ts
和 split
的副本卡在后台。可能相互连接成功,这可以解释缺少错误消息。
你可能打算写
ts '[%Y-%m-%d %H:%M:%S]' > >(split -d -b 10 -)
^
重定向到进程替换。
也就是说,您可以在 ts
和 split
之间使用管道。
我试图在 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 字节文件(上面没有时间戳) . - 这是我所期望的并且是有意义的,因为 T 恤分别重定向到两个进程替换,这主要是一个完整性检查
我认为正在发生的事情
据我所知,>(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
,进程替换 tee
将其发送到进程替换 ts
并添加将其发送到 split
的时间戳并将输出拆分为多个小文件。
感谢您抽出宝贵时间以及您可能提供的任何帮助。
*Edit - 我刚刚尝试 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
然后尝试打开进入 split
的 fd
以从那里读取输入,而不是从原始标准输入读取。
这可能不是你想要的,在我的机器上,我在测试时得到了一些 ts
和 split
的副本卡在后台。可能相互连接成功,这可以解释缺少错误消息。
你可能打算写
ts '[%Y-%m-%d %H:%M:%S]' > >(split -d -b 10 -)
^
重定向到进程替换。
也就是说,您可以在 ts
和 split
之间使用管道。