1

I'm trying to transition away from my ad-hoc build script, which iterates over all children of the project's home, and creates a corresponding zip file for each:

for i in */; do
    if [[ -d $i ]]; then
        echo "Processing folder $i";
        zip "${i%/}.zip" "$i"*.txt
        echo "Created ${i%/}.zip"
    fi
done;

The first line is clunky, but it's just iterating through all subdirs excluding hidden ones. As you can see the logic is straightforward, but doing this in a Makefile without explicitly specifying each subdirectory seems difficult.

Ideally we should start with:

project
  subdir1
    file1.txt
    file2.txt
  subdir2
    file3.txt

...and end up with:

project
  subdir1
    file1.txt
    file2.txt
  subdir1.zip
  subdir2
    file3.txt
  subdir2.zip

Is there a way to safely get this sort of recursion out of make?

edit: Cleaned up base script, thanks Etan

Zac
  • 1,569
  • 1
  • 11
  • 10
  • 1
    Your original script is not safe for directories with spaces or shell metacharacters just FYI. Using `for i in */; do` would be though. The inner find may have similar problems with spaces/newlines in file names depending on how `zip` handles its input. If your tree isn't deeply nested using `zip "$i.zip" "$i"/*.txt`/etc. instead is safer. – Etan Reisner Mar 03 '15 at 23:41
  • You can just put that exact script in a target of your makefile if you wanted to. – Etan Reisner Mar 03 '15 at 23:41
  • @EtanReisner Thanks for comments on the script (will be editing it). I know I can just throw that into a Makefile, but was thinking there might be a "right" way to do it in make syntax. – Zac Mar 03 '15 at 23:45
  • 1
    Do you just need the toplevel directories zipped? You could glob the directories and make targets for all of them if you wanted to do this in make. – Etan Reisner Mar 03 '15 at 23:46
  • @EtanReisner Yes, just the toplevel. I think that's exactly what I was looking for. Similar question here: http://stackoverflow.com/questions/8937500/how-to-generate-list-of-make-targets-automatically-by-globbing-subdirectories. Appreciate the help! – Zac Mar 03 '15 at 23:55

1 Answers1

5

Something like this might do what you want.

SUBDIRS := $(wildcard */)
ZIPS := $(addsuffix .zip,$(subst /,,$(SUBDIRS)))

$(ZIPS) : %.zip : | %
    zip $@ $*/*.txt

dist: $(ZIPS)

You might need to adjust the prerequisites on that static pattern rule, etc. to get the correct rebuilding behavior (should make detect when it needs to rebuild, should it always rebuild, should it never rebuild when the .zip file exists, etc).

Etan Reisner
  • 77,877
  • 8
  • 106
  • 148
  • Hmm, when I run that in a test dir, I get a miss on the pattern for the zip: `zip warning: name not matched: %*/*.txt`. I'll have to take a look at the specific substitution error, but your solution is exactly what I was looking for. – Zac Mar 04 '15 at 23:04
  • 1
    That's because I typo-ed it. Try `$*/*.txt` . – Etan Reisner Mar 05 '15 at 02:41