How to use shell commands in a makefile

I am trying to use the ls result in other commands (e.g. echo, rsync):

 all: <Building, creating some .tgz files - removed for clarity> FILES = $(shell ls) echo $(FILES) 

But I get:

 make FILES = Makefile file1.tgz file2.tgz file3.tgz make: FILES: No such file or directory make: *** [all] Error 1 

I tried using echo $$FILES , echo ${FILES} and echo $(FILES) , no luck.

+53
bash echo makefile macos
Apr 05 '12 at 7:25
source share
2 answers

FROM

 FILES = $(shell ls) 

indented under all , like this, this is a build command. Thus, it extends $(shell ls) , then tries to run the FILES ... command.

If FILES assumed to be a make variable, these variables must be assigned outside of the recipe, for example:

 FILES = $(shell ls) all: echo $(FILES) 

Of course, this means that FILES will be set to "output from ls " before running any of the commands that create the .tgz files. (Although the variable is re-expanded each time as Kaz notes , therefore it will eventually include .tgz files, and some of the options have FILES := ... to avoid this, for efficiency and / or correctness. 1 )

If FILES assumed to be a shell variable, you can set it, but you need to do this in shell-ese without spaces and quote:

 all: FILES="$(shell ls)" 

However, each line is launched by a separate shell, so this variable will not be saved until the next line, so you should use it immediately:

  FILES="$(shell ls)"; echo $$FILES 

This is a little silly, as the shell will expand * (and other shell shell expressions) for you in the first place, so you can simply:

  echo * 

as your shell command.

Finally, as a general rule (actually not applicable to this example): as esperanto notes in the comments, the use of the output from ls not complete (some details depend on the file names, and sometimes on the version of ls , some versions of ls try to then measure misinform the conclusion). So, like l0b0 and idelic, note that if you use GNU make, you can use $(wildcard) and $(subst ...) to do everything inside make (avoiding the "strange characters in the file name" problems). (In sh scripts, including part of the make-file recipes, another method is to use find ... -print0 | xargs -0 to avoid tripping over spaces, newlines, control characters, etc.)




1 GNU Make more documentation that POSIX adds ::= in 2012 . I did not find a link to link to a POSIX document for this, and I donโ€™t know what make options support ::= , although GNU make today with the same value as := , i.e. complete the task right now with the extension.

Please note that VAR := $(shell command args...) can also be written VAR != command args... in several make variants, including all modern GNU and BSD variants, as far as I know. These other options do not have $(shell) , so using VAR != command args... superior to both shrinking and working in more options.

+73
Apr 05 2018-12-12T00:
source share

Also, in addition to torek's answer: one thing that stands out is that you are using a lazily evaluated macro assignment.

If you use GNU Make, use := instead of = . This assignment causes the right side to immediately expand and be stored in the left 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 = , this means that every single occurrence of $(FILES) will extend the syntax of $(shell ...) and thus invoke the shell command. This will make your work run slower or even have some unexpected consequences.

+26
Apr 09 '12 at 23:22
source share



All Articles