How to use shell commands in Makefile
With:
FILES = $(shell ls)
indented underneath all
like that, it's a build command. So this expands $(shell ls)
, then tries to run the command FILES ...
.
If FILES
is supposed to be a make
variable, these variables need to be assigned outside the recipe portion, e.g.:
FILES = $(shell ls)
all:
echo $(FILES)
Of course, that means that FILES
will be set to "output from ls
" before running any of the commands that create the .tgz files. (Though as Kaz notes the variable is re-expanded each time, so eventually it will include the .tgz files; some make variants have FILES := ...
to avoid this, for efficiency and/or correctness.1)
If FILES
is supposed to be a shell variable, you can set it but you need to do it in shell-ese, with no spaces, and quoted:
all:
FILES="$(shell ls)"
However, each line is run by a separate shell, so this variable will not survive to the next line, so you must then use it immediately:
FILES="$(shell ls)"; echo $$FILES
This is all a bit silly since the shell will expand *
(and other shell glob expressions) for you in the first place, so you can just:
echo *
as your shell command.
Finally, as a general rule (not really applicable to this example): as esperanto notes in comments, using the output from ls
is not completely reliable (some details depend on file names and sometimes even the version of ls
; some versions of ls
attempt to sanitize output in some cases). Thus, as l0b0 and idelic note, if you're using GNU make you can use $(wildcard)
and $(subst ...)
to accomplish everything inside make
itself (avoiding any "weird characters in file name" issues). (In sh
scripts, including the recipe portion of makefiles, another method is to use find ... -print0 | xargs -0
to avoid tripping over blanks, newlines, control characters, and so on.)
1The GNU Make documentation notes further that POSIX make added ::=
assignment in 2012. I have not found a quick reference link to a POSIX document for this, nor do I know off-hand which make
variants support ::=
assignment, although GNU make does today, with the same meaning as :=
, i.e., do the assignment right now with expansion.
Note that VAR := $(shell command args...)
can also be spelled VAR != command args...
in several make
variants, including all modern GNU and BSD variants as far as I know. These other variants do not have $(shell)
so using VAR != command args...
is superior in both being shorter and working in more variants.
Also, in addition to torek's answer: one thing that stands out is that you're using a lazily-evaluated macro assignment.
If you're on GNU Make, use the :=
assignment instead of =
. This assignment causes the right hand side to be expanded immediately, and stored in the left hand variable.
FILES := $(shell ...) # expand now; FILES is now the result of $(shell ...)
FILES = $(shell ...) # expand later: FILES holds the syntax $(shell ...)
If you use the =
assignment, it means that every single occurrence of $(FILES)
will be expanding the $(shell ...)
syntax and thus invoking the shell command. This will make your make job run slower, or even have some surprising consequences.