22

I want to do an operation on all the files in a particular folder that do not start with a particular prefix (say exclude_). I have a bash for loop with an extended glob that looks like this:

for FILE in foo/bar/!(exclude_*) ; do echo $FILE ; done

On the command line, this works fine:

 $ for FILE in foo/bar/!(exclude_*) ; do echo $FILE ; done
 foo/bar/apple
 foo/bar/pear
 foo/bar/banana

But, when I use it in a makefile:

target:
    for FILE in foo/bar/!(exclude_*) ; do echo $$FILE ; done

I get the following error:

$ make
for FILE in foo/bar/!(exclude_*) ; do echo $FILE ; done
/bin/sh: -c: line 0: syntax error near unexpected token `('
/bin/sh: -c: line 0: `for FILE in foo/bar/!(exclude_*) ; do echo $FILE ; done'

Is there some necessary escaping that I've missed?

Timothy Jones
  • 349
  • 1
  • 2
  • 7

4 Answers4

13

It would be more idiomatic and more portable to solve this with Make and not with Bash hacks. What if someone doesn't have Bash installed?

Anyway, here's the proper way to do it in Make:

FOOFILES = $(filter-out foo/bar/exclude_%,$(wildcard foo/bar/*))

target:
    for FILE in ${FOOFILES}; do echo $$FILE ; done
Timothy Jones
  • 349
  • 1
  • 2
  • 7
12
  1. You need to set extglob.
  2. You need to tell make to use bash, not sh.

Makefile:

SHELL=/bin/bash
.SHELLFLAGS="-O extglob -c"
 ...
Ignacio Vazquez-Abrams
  • 111,361
  • 10
  • 201
  • 247
  • 3
    Hmm. For some reason the `.SHELLFLAGS` didn't work for me, but putting the flags directly in `SHELL=/bin/bash -O extglob -c` did. Any ideas why? – Timothy Jones Jul 15 '13 at 06:01
  • 1
    Maybe you're not using GNU make. Or maybe it doesn't need the quotes. – Ignacio Vazquez-Abrams Jul 15 '13 at 06:01
  • GNU Make 3.81, and GNU bash, version 4.1.2. Tried without the quotes too. Weird. – Timothy Jones Jul 15 '13 at 06:02
  • 1
    Anyway, your answer solved it for me once I put them all on the one line. Thanks! – Timothy Jones Jul 15 '13 at 06:03
  • @TimothyJones Hi, I tried your method. But why I got errors? SHELL=/bin/bash -O extglob -c /bin/sh: -O: command not found make: *** [mpip] Error 127 – user15964 Apr 10 '16 at 14:03
  • I was trying to use `SHELL := /bin/bash +O extglob`, but that didn't work. I wonder why. Your method didn't work for me, though, either. I got "`/bin/bash: - : invalid option`." – Geremia Jan 05 '17 at 16:22
  • 1
    The `.SHELLFLAGS` variable was added in GNU make 3.82. You can check which features were added in which releases via the NEWS file: http://git.savannah.gnu.org/cgit/make.git/tree/NEWS – MadScientist Feb 12 '17 at 17:06
  • `.SHELLFLAGS` worked for me with GNU Make 3.82, but only without the quotes – Koen G. Oct 22 '19 at 08:37
4

Here is a simpler way:

SHELL:=/bin/bash -O globstar

which will enable globstar shell option (which works on BSD/OS X as well).

kenorb
  • 24,736
  • 27
  • 129
  • 199
0

Add this to the top of the Makefile:

SHELL := bash -O extglob
Geremia
  • 546
  • 1
  • 7
  • 28