我正在尝试在其他命令中使用ls
的结果(例如echo,rsync):
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)
,但没有运气。
答案 0 :(得分:113)
使用:
FILES = $(shell ls)
在all
下面缩进,这是一个构建命令。因此,这会扩展$(shell ls)
,然后尝试运行命令FILES ...
。
如果FILES
应该是make
变量,则需要在配方部分之外分配这些变量,例如:
FILES = $(shell ls)
all:
echo $(FILES)
当然,这意味着在运行创建.tgz文件的任何命令之前,FILES
将设置为“ls
”的输出。 (虽然每次重新扩展变量为Kaz notes,但最终它将包含.tgz文件;为了效率和/或正确性,一些变体使用FILES := ...
来避免这种情况。 1 )
如果FILES
应该是一个shell变量,你可以设置它,但你需要在shell-ese中做,没有空格,并引用:
all:
FILES="$(shell ls)"
但是,每一行都由一个单独的shell运行,因此这个变量不会存活到下一行,所以你必须立即使用它:
FILES="$(shell ls)"; echo $$FILES
这有点傻,因为shell会首先为你扩展*
(以及其他shell glob表达式),所以你可以这样做:
echo *
作为你的shell命令。
最后,作为一般规则(不适用于此示例):作为注释中的esperanto注释,使用ls
的输出并不完全可靠(某些细节取决于文件名,有时候甚至是ls
的版本;某些版本的ls
在某些情况下会尝试清理输出。因此,正如l0b0和idelic注意,如果您使用GNU make,则可以使用$(wildcard)
和$(subst ...)
来完成make
内部的所有内容(避免任何内容) “文件名中的奇怪字符”问题)。 (在sh
脚本中,包括makefile的配方部分,另一种方法是使用find ... -print0 | xargs -0
来避免跳过空格,换行符,控制字符等。)
1 The GNU Make documentation notes further that POSIX make added ::=
assignment in 2012。我没有为此找到POSIX文档的快速参考链接,也不知道哪些make
变体支持::=
赋值,尽管GNU make今天做了,其含义与{{{ 1}},即现在通过扩展进行分配。
请注意:=
也可以在几个VAR := $(shell command args...)
变体中拼写VAR != command args...
,据我所知,包括所有现代GNU和BSD变体。这些其他变体没有make
因此使用$(shell)
在更短的和更多变种中都是优越的。
答案 1 :(得分:39)
此外,除了torek的答案之外:有一点很突出,那就是你正在使用懒惰评估的宏分配。
如果您使用的是GNU Make,请使用:=
分配而不是=
。此分配使右侧立即展开,并存储在左侧变量中。
FILES := $(shell ...) # expand now; FILES is now the result of $(shell ...)
FILES = $(shell ...) # expand later: FILES holds the syntax $(shell ...)
如果使用=
赋值,则意味着每次出现$(FILES)
都会扩展$(shell ...)
语法,从而调用shell命令。这将使你的制作工作运行得更慢,甚至会产生一些令人惊讶的后果。