Search code examples
bashpipepipelineconditional-execution

How to conditionally add a pipeline element in bash


I need to form a pipeline of various commands. Some elements of the pipeline, or sequences of elements, are only relevant when some condition holds. Now, I could write:

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

but that means repeating cmd1 and cmd4, plus, there may be several conditions and I don't want to write nested if's. So, I tried writing this:

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

cmd1 ${pipeline_segment} | cmd4

but - the pipe symbol was not interpreted as an instruction to use a pipe.

How do I have bash execute the pipeline I want it too?

Note: You may assume a bash version of 4 or higher, but only if you must.


Solution

  • Your attempt fails because special symbols lose their syntactical value after expansion. eval is a way, but as we know it is prone to code injection so it is best avoided. We can try

    cmd1 |
    if [ condition ]; then
       cmd2 | cmd3
    else
       cat
    fi | 
    cmd4
    

    Though I'd love to skip cat, I couldn't find a way. Real example:

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

    outputs ABCABC and changing the condition to false outputs AYZABC.