Nick
Nick

Reputation: 7

How can I use an "if" to generate part of a shell pipeline?

I have code like the following:

if foo; then
  bar |
else
  baz |
fi
qux

...intended to evaluate to either bar | qux or baz | qux, depending on whether foo is true.

More specifically:

if [ -f path/file.txt ]
then
    find "/home/repo/sources" -type f '(' -name '*.upl' -o -name '*.int' -o -name '*.ini' -o -name '*.txt' -o -name '*.htm' -o -name '*.inc' -o -name '*.css' -o -name '*.example' -o -name '*.cfg' -o -name '*.cache' -o -name '*.manifest' -o -name '*.dsp' -o -name '*.vdf' -o -name '*.lst' -o -name '*.gam' -o -name '*.scr' -o -name '*.nut' -o -name '*.db' -o -name '*.inf' -o -name '*.rc' -o -name '*.bsp' -o -name '*.nav' ')' -printf '%P\0' |
else
    find "/home/repo/sources" -type f '(' -name '*.upl' -o -name '*.int' -o -name '*.ini' -o -name '*.txt' -o -name '*.htm' -o -name '*.inc' -o -name '*.css' -o -name '*.example' -o -name '*.cfg' -o -name '*.cache' -o -name '*.manifest' -o -name '*.dsp' -o -name '*.vdf' -o -name '*.lst' -o -name '*.gam' -o -name '*.scr' -o -name '*.nut' -o -name '*.db' -o -name '*.inf' -o -name '*.rc' -o -name '*.nav' ')' -printf '%P\0' |
fi

My error:

/home/repo/sources/test.sh: line 2207: syntax error near unexpected token `else'
/home/repo/sources/test.sh: line 2207: `else'

If i remove the all the if statment and just put one of the find's it will work without any errors. After the find outside the If statment I have this: while IFS= read -r -d '' file; do

Upvotes: 0

Views: 53

Answers (2)

Gordon Davisson
Gordon Davisson

Reputation: 125788

Charles Duffy's answer provides a better way to do this that avoids the whole issue, but just for the record I'd like to answer how to make part of a pipeline conditional. The short answer is that you can't interleave shell syntaxes, like having part of a pipeline inside an if statement and another part outside. You can have a pipeline inside an if, or an if inside one stage of a pipeline (or even an if inside a pipeline inside an if inside...), but they have to nest, one inside the other.

In this case, the nesting is easy to achieve: put the if fully inside a stage of the pipeline, by simply moving the | after then:

if foo; then
  bar
else
  baz
fi |
qux

Upvotes: 0

Charles Duffy
Charles Duffy

Reputation: 295363

I'd strongly suggest writing this to only run find once, and branch in setting up your array. For example:

# set up a simple array with all the names common to both lists
types=( cache cfg css db dsp example gam htm inc inf ini int lst manifest
        nav nut rc scr txt upl vdf )

# branch *here*, deciding whether to append an extra type to the list
[ -f path/file.txt ] && types+=( bsp )

# convert our list, whatever it contains, to a list of arguments to find
findArgs=( -false )
for type in "${types[@]}"; do
  findArgs+=( -o -name "*.$type" )
done

# expand that list
find . '(' "${findArgs[@]}" ')' -printf '%P\0'

This is in accordance with section 1.5 of BashFAQ #50.

Upvotes: 3

Related Questions