Reputation: 439
Consider the makefile below :
CFG_DIR = /media/test/
all:
for list in $(CFG_DIR); do \
echo "list is $$list"; \
for file in $(shell ls $${list}); do \
echo "file is $$file"; \
done \
done
When make is executed the below result is generated:
list is /media/test/
file is Makefile
Instead of printing the directory listing of /media/test/ directory, directory listing of the current directory from where the make command is executed is printed.
It seems like within the shell function $$list is being evaluated to an empty value. It would be helpful if someone can point out the correct way to access for loop variables inside shell function.
Upvotes: 0
Views: 2557
Reputation: 100816
You can't use a shell variable in a make function.
Consider how make works: when it wants to run a recipe command FIRST it expands all the make variables and functions in the command, THEN it takes the resulting string and passes it to a shell to run, THEN it waits for the shell to exit. If the shell exits with a success code (0) then make says "yay it worked!" If the shell exits with a failure code (non-0) then make says "boo it failed."
Here's your recipe:
for list in $(CFG_DIR); do \
echo "list is $$list"; \
for file in $(shell ls $${list}); do \
echo "file is $$file"; \
done \
done
So, FIRST make will expand this including all variables and functions. You have a $(CFG_DIR)
variable, and a $(shell...)
function. The variable is simply /media/test/
. When make expands the function, it sees the command to pass to the shell is ls ${list}
. So make runs:
/bin/sh -c 'ls ${list}'
Well, unless you've set the shell variable list
in your environment somewhere it's the empty string, so the shell executes ls
and returns all the contents of your current directory. Then, make substitutes that into your recipe, and hands the results to the shell to run:
/bin/sh -c 'for list in /media/test; do
echo "list is $list";
for file in <current-wd-files>; do
echo "file is $file";
done
done'
So. Moral of the story: in a recipe command you're already in a shell. So you should never use the $(shell ...)
make function. It will only lead to confusion and sorrow.
You should use shell syntax since you already have a shell:
all:
for list in $(CFG_DIR); do \
echo "list is $$list"; \
for file in `ls $${list}`; do \
echo "file is $$file"; \
done \
done
Upvotes: 1