通过管道输出到 T 形件会破坏条件

通过管道输出到 T 形件会破坏条件

我正在尝试测试服务器上是否存在自定义防火墙规则。我通过使用 awk 处理 iptables 输出并返回适当的退出代码来完成此操作。这按预期工作,并打印了正确的结果。然而,当它通过管道传输到 tee 时,条件不再起作用,并且每次都会打印结果。

# The broken code
ssh server1 'sudo iptables -L | awk "(!/ACCEPT/ && !/^target/ && !/^$/) {rules=1 ;} (rules==1) {exit 1}" && printf "%s\n" "string1" "string2" | sudo tee -a /path/to/file'
# The same code without `| sudo tee -a /path/to/file` works as intended
ssh server1 'sudo iptables -L | awk "(!/ACCEPT/ && !/^target/ && !/^$/) {rules=1 ;} (rules==1) {exit 1}" && printf "%s\n" "string1" "string2"'

我缺少什么?我在 RHEL8 上使用 GNU coretils 8.30 和 GNU bash 版本 4.4.20(1)。我刚刚注意到 awk 语句可以缩短,但这不是重点:D

答案1

您的投诉主要围绕管道返回的状态iptables ... | awk ... && printf ... | tee ... 。狂欢文档 解释了它的价值是什么。

除非启用了 pipelinefail 选项,否则管道的返回状态是最后一个命令的退出状态。如果启用了pipefail,则管道的返回状态是最后一个(最右边)以非零状态退出的命令的值,如果所有命令成功退出,则返回零。

考虑执行

set -o pipefail

在管道结果之前。

或者,如果您发现更简单的话,可以使用... | (cmd ... || true) | ...习惯用法,以便每个阶段都会返回。0在检测到异常情况时发出独特的消息,以便稍后的管道阶段可以grep处理它。

让 bash 有条件地协调 awk 的简单处理和 printf 的简单处理的设计决策在当时可能是有意义的,但现在您发现它拖累了生产力。考虑将该逻辑合并到一个简单的 awk 脚本中。


您可能会发现运行较短的管道更方便。

ssh server1 ... | awk ...  > server1.txt
# awk exit status is now available in $? so you can conditionally run printf

cat server1.txt  >> /path/to/file

在最初的问题中, /path/to/file 是一个服务器路径名,我们正在运行一个具有一定复杂性的单行远程管道。您可能会发现iptables -L 通过 ssh 连接返回原始输出并运行本地管道更方便。生成本地结果文件后,您始终可以将其存储为:

cat results.txt | ssh server1 'cat >> /path/to/file'

相关内容