16

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?

8
  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"
 ...
| improve this answer | |
  • 2
    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 6:01
  • 1
    Maybe you're not using GNU make. Or maybe it doesn't need the quotes. – Ignacio Vazquez-Abrams Jul 15 '13 at 6:01
  • GNU Make 3.81, and GNU bash, version 4.1.2. Tried without the quotes too. Weird. – Timothy Jones Jul 15 '13 at 6:02
  • Anyway, your answer solved it for me once I put them all on the one line. Thanks! – Timothy Jones Jul 15 '13 at 6:03
  • 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: git.savannah.gnu.org/cgit/make.git/tree/NEWS – MadScientist Feb 12 '17 at 17:06
11

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
| improve this answer | |
2

Here is a simpler way:

SHELL:=/bin/bash -O globstar

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

| improve this answer | |
0

Add this to the top of the Makefile:

SHELL := bash -O extglob
| improve this answer | |
  • 1
    Doesn't work. The above version is correct. – Desik Sep 21 '18 at 7:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.