【问题标题】:Conditional step in a pipeline管道中的条件步骤
【发布时间】:2017-01-18 07:56:50
【问题描述】:

给定一个类似于“A|B|C|D|E”的管道,我想让步骤 C 以步骤 B 的结果为条件。像这样:

A | B | if [ $? -ne 0 ]; then C; else cat; fi | D | E

但这似乎不起作用;无论 B 的结果如何,C 都不会执行。我正在寻找更好的解决方案。

我了解管道的每个步骤都在其自己的子外壳中运行。所以我不能将环境变量传递回管道。但是这个管道是在一个 Gnu Parallel 环境中,其中许多这样的管道同时运行并且它们都不知道任何唯一值(它们只处理数据流并且不需要知道源,父脚本处理必要的分离)。这意味着使用临时文件也不可行,因为没有任何方法可以使文件名唯一。甚至 $$ 似乎也没有在每个步骤中给我一个相同的值。

【问题讨论】:

  • 您可能会查看set -o pipefail,但更现实的是,您只需要分解命令而不是使用单个管道。

标签: bash pipeline environment


【解决方案1】:

您不能将管道设置为有条件的,因为命令是并行运行的。如果C 直到B 退出才运行,那么B 的输出将通过管道传输到哪里?

您需要将B 的输出存储在变量或临时文件中。例如:

out=$(mktemp)
trap 'rm "$out"' EXIT
if A | B > "$out"; then
    C < "$out"
else
    cat "$out"
fi | D | E

【讨论】:

  • 这看起来像是我需要的解决方案。谢谢。
  • 把它放到一个函数中,export -f 它,它已经为 GNU Parallel 做好了准备
  • 您可以使用 $PARALLEL_TMP,而不是 mktemptrap
【解决方案2】:

你陈述问题的方式在逻辑上是不可能的。

假设像A | B 这样的管道。管道的存在特别是因为我们希望 B 在 A 完成之前开始从 A 读取。因此,当 B 启动时(即评估您的条件时),A 还不知道它是失败还是成功,所以 B 也不知道。

你可以做的是,有一个回声,作为它的最后一行,某种类型的状态代码。然后 B 可以从标准输入中读取,保存输入(作为临时文件,保存到变量中),然后一旦收到最后一行,检查状态然后采取行动。

当然,另一种方法是让 A 存储它自己的输出,然后在它完成后,在 A 内部添加条件(并从管道中消除 B)。

【讨论】:

  • 啊...当然...有时我会迷失在细节中。感谢您提醒我管道是如何工作的。
猜你喜欢
  • 2016-10-08
  • 2023-04-08
  • 1970-01-01
  • 2017-10-15
  • 1970-01-01
  • 2017-11-14
  • 1970-01-01
  • 2021-01-28
  • 2020-08-15
相关资源
最近更新 更多