如何在Makefile中使用shell命令
我试图在其他命令(例如echo,rsync)中使用ls
的结果:
all: <Building, creating some .tgz files - removed for clarity> FILES = $(shell ls) echo $(FILES)
但是我得到:
make FILES = Makefile file1.tgz file2.tgz file3.tgz make: FILES: No such file or directory make: *** [all] Error 1
我试过使用echo $$FILES
, echo ${FILES}
和echo $(FILES)
,没有运气。
附:
FILES = $(shell ls)
在all
这些下面缩进,这是一个构build命令。 所以这扩展了$(shell ls)
,然后尝试运行命令FILES ...
如果FILES
应该是一个make
variables,则这些variables需要在配方部分之外进行分配,例如:
FILES = $(shell ls) all: echo $(FILES)
当然,这意味着在运行任何创build.tgz文件的命令之前 , FILES
将被设置为“从ls
输出”。 (虽然Kaz注意到这个variables每次都被重新扩展,所以最终会包含.tgz文件;为了避免这种情况,为了提高效率和/或正确性,一些变体有FILES := ...
1 )
如果FILES
应该是一个shellvariables,你可以设置它,但是你需要在shell-ese中完成,没有空格,并引用:
all: FILES="$(shell ls)"
但是,每行都由一个单独的shell运行,所以这个variables将不能存活到下一行,因此您必须立即使用它:
FILES="$(shell ls)"; echo $$FILES
这有点傻,因为shell首先会为你扩展*
(和其他shell globexpression式),所以你可以:
echo *
作为你的shell命令。
最后,作为一般规则(不适用于这个例子):作为注释中的世界语笔记,使用来自ls
的输出不是完全可靠的(一些细节取决于文件名,有时甚至是ls
的版本;某些版本的ls
尝试在某些情况下消毒产量)。 因此,如l0b0和idelic所示 ,如果你使用的是GNU,你可以使用$(wildcard)
和$(subst ...)
来完成内部的一切(避免文件名中的“奇怪字符”问题)。 (在sh
脚本中,包括makefile的配方部分,另一种方法是使用find ... -print0 | xargs -0
来避免跳过空格,换行符,控制字符等等。
1 GNU Make文档还注意到POSIX在2012年增加了::=
赋值 。 我还没有find一个POSIX文档的快速参考链接,我也不知道哪些变体支持::=
赋值,虽然GNU make今天做的,具有相同的含义:=
,即做任务现在扩大。
请注意, VAR := $(shell command args...)
也可以拼写为VAR != command args...
在几个变种,包括所有现代的GNU和BSD变种据我所知。 这些其他的变体没有$(shell)
所以使用VAR != command args...
在更短和工作更多的变种是优越的。
另外,除了torek的回答之外,还有一点很突出,就是你正在使用懒惰评估的macros分配。
如果您使用的是GNU Make,请使用:=
赋值而不是=
。 这个赋值使得右侧立即被扩展,并存储在左侧variables中。
FILES := $(shell ...) # expand now; FILES is now the result of $(shell ...) FILES = $(shell ...) # expand later: FILES holds the syntax $(shell ...)
如果使用=
赋值,则意味着$(FILES)
每一次出现都将扩展$(shell ...)
语法,从而调用shell命令。 这会让你的工作变慢,甚至会有一些令人惊讶的后果。