如何在Bash中有条件地添加管道元素

3

我需要创建一个由各种不同命令组成的管道。管道中的某些元素或元素序列只有在满足特定条件时才相关。现在,我可以这样写:

if [[ $whatever ]]; then
   cmd1 | cmd2 | cmd3 | cmd4
else
   cmd1 | cmd4
fi

但这意味着需要重复cmd1cmd4,而且可能有几个条件,我不想写嵌套的if语句。所以,我尝试写出以下代码:

if [[ $whatever ]]; then
    pipeline_segment="| cmd2 | cmd3"
else
    pipeline_segment=""
fi

cmd1 ${pipeline_segment} | cmd4

但是,管道符号没有被解释为使用管道的指令。

我应该如何让bash执行我想要的管道?

注意:如果必须,您可以假设bash版本为4或更高版本。


1
评估 "cmd1 ${pipeline_segment} | cmd4" 可能吗? - undefined
eval或将提交给ssh的复合命令类似:bash -c "cmd1 ${pipeline_segment} | cmd4"(请注意可能需要转义嵌入的双引号等) - undefined
非常相似:Bash中的条件流水线 - undefined
2个回答

8
你的尝试失败是因为特殊符号在扩展后失去了其句法价值。 eval 是一种方法,但我们知道它容易受到代码注入攻击,所以最好避免使用。我们可以尝试:
cmd1 |
if [ condition ]; then
   cmd2 | cmd3
else
   cat
fi | 
cmd4

虽然我很想跳过cat命令,但我找不到方法。以下是真实的例子:

echo XYZABC |
if true; then
   tr Y B | tr Z C
else
   cat
fi | 
tr X A

输出为ABCABC,将条件更改为false时输出AYZABC


在那里放一只猫没有什么问题。如果这是一个问题,可以通过启用可加载的内置“tee”并使用它来避免额外的开销。 - undefined
我曾考虑使用“cat”。但是,对于大文件来说,那会导致显著的性能损耗吗? - undefined
@oguzismail: "可加载的内置T恤"是什么意思? - undefined
@einpoklum Bash附带了各种可加载的内建命令,tee就是其中之一。在我的系统中,它们存储在/usr/lib/bash目录下,我可以使用enable -f /usr/lib/bash/tee tee命令将tee设置为内建命令。 - undefined
@oguzismail:哦,那真是个好主意。你能把它写成一个答案吗? - undefined
可能是,但是我猜你的其他命令比cat要复杂得多(至少如果它们是文本处理命令的话)。 - undefined

6

我猜您不想重复任何东西,因为它们是很庞大且难以理解的命令。在这种情况下,可以使用函数来封装它们:

cmd1() { some big long command with many options and arguments; }
cmd2() { similar; }
... and so on

你可以直接使用这个

if [[ $whatever ]]; then
   cmd1 | cmd2 | cmd3 | cmd4
else
   cmd1 | cmd4
fi

或者将“whatever”条件推入函数中:
cmd2 () { 
    if [[ whatever ]]; then
        the big long command
    else
        cat
    fi
}
cmd3() {
    if [[ whatever ]]; then
        the other big long command
    else
        cat
    fi
}

那么,你只需要留下简单的
cmd1 | cmd2 | cmd3 | cmd4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接