[英]How to use shell commands in Makefile
我正在尝试在其他命令(例如 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
是一个构建命令。 所以这扩展$(shell ls)
,然后尝试运行命令FILES...
。
如果FILES
应该是make
变量,则需要在配方部分之外分配这些变量,例如:
FILES = $(shell ls)
all:
echo $(FILES)
当然,这意味着在运行任何创建 .tgz 文件的命令之前, FILES
将被设置为“从ls
输出”。 (尽管Kaz 指出变量每次都会重新扩展,因此最终它将包含 .tgz 文件;一些 make 变体具有FILES:=...
以避免这种情况,以提高效率和/或正确性。1 )
如果FILES
应该是一个 shell 变量,你可以设置它,但你需要在 shell-ese 中进行,没有空格,并引用:
all:
FILES="$(shell ls)"
但是,每一行都由一个单独的 shell 运行,所以这个变量不会存活到下一行,所以你必须立即使用它:
FILES="$(shell ls)"; echo $$FILES
这有点傻,因为 shell 首先会为你扩展*
(和其他 shell glob 表达式),所以你可以:
echo *
作为您的 shell 命令。
最后,作为一般规则(并非真正适用于此示例):正如世界语在评论中指出的那样,使用ls
中的output并不完全可靠(一些细节取决于文件名,有时甚至取决于ls
的版本;某些版本的ls
尝试在某些情况下对 output 进行消毒)。 因此,作为l0b0和idelic注释,如果您正在使用 GNU make,则可以使用$(wildcard)
和$(subst...)
来完成make
自身内部的所有操作(避免任何“文件名中的奇怪字符”问题)。 (在sh
脚本中,包括 makefile 的配方部分,另一种方法是使用find... -print0 | xargs -0
来避免被空格、换行符、控制字符等绊倒。)
1 GNU Make 文档进一步指出 POSIX make 在 2012 年添加了::=
赋值。 我没有为此找到指向 POSIX 文档的快速参考链接,我也不知道哪些变体支持::=
赋值,尽管 GNU make
今天支持,与:=
具有相同的含义,即进行赋值现在随着扩张。
请注意, VAR:= $(shell command args...)
也可以拼写为VAR.= command args...
在几个make
变体中,包括据我所知的所有现代 GNU 和 BSD 变体。 这些其他变体没有$(shell)
因此使用VAR.= command args...
在更短和在更多变体中工作方面更胜一筹。
此外,除了 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 命令。 这将使您的 make 作业运行得更慢,甚至会产生一些令人惊讶的后果。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.