Shell – avoid multiple pipes broken due to missing command

pipeportabilityshell-script

In shell scripts I often use multiple pipes like this:

cmd1 | cmd2 | cmd3

Now if cmd2 is missing the pipe will result "broken" and cmd3 won't receive any input.

As workaround I could test explicitly if cmd2 exist, but this requires some code replication I'd like to avoid.

Instead I'd like a more concise test like this:

cmd1 | cmd2; [ $? -eq 127 ] && cat | cmd3

Best Answer

Based on your example it looks like you're looking for a way to group arguments to operations with lower precedence than |, (i.e. && and ||).

The { and } metacharacters can be used for grouping in this way.

Your example above could be written like this (using the exit status of which to determine whether cmd2 exists or not).

cmd1 | { which cmd2 >/dev/null && cmd2 || cat; } | cmd3

For example

printf "hi\n" | { : && rev || cat; } | cat

Will print ih

Your suggestion of using a subshell will also work, but uses another process unnecessarily

printf "hi\n" | ( : && rev || cat ) | cat

I would say it is probably less tricky and better for maintainability if you use an explicit if outside the pipe.

if [ which cmd2 >/dev/null ]
then
    cmd1 | cmd3
else
    cmd1 | cmd2 | cmd3
fi