Bash 如何在Makefile中使用shell命令
我试图在其他命令(例如echo、rsync)中使用Bash 如何在Makefile中使用shell命令,bash,makefile,echo,Bash,Makefile,Echo,我试图在其他命令(例如echo、rsync)中使用ls的结果: 我尝试过使用echo$$FILES,echo${FILES}和echo$(FILES),但运气不佳。使用了: FILES = $(shell ls) 在all下面缩进,就像那样,这是一个构建命令。因此,这将展开$(shell ls),然后尝试运行命令文件… 如果文件应该是make变量,则需要在配方部分之外分配这些变量,例如: FILES = $(shell ls) all: echo $(FILES) 当然,这意
ls
的结果:
我尝试过使用echo$$FILES
,echo${FILES}
和echo$(FILES)
,但运气不佳。使用了:
FILES = $(shell ls)
在all
下面缩进,就像那样,这是一个构建命令。因此,这将展开$(shell ls)
,然后尝试运行命令文件…
如果文件
应该是make
变量,则需要在配方部分之外分配这些变量,例如:
FILES = $(shell ls)
all:
echo $(FILES)
当然,这意味着在运行创建.tgz文件的任何命令之前,FILES
将被设置为“output fromls
”。(尽管变量每次都会重新展开,因此最终它将包含.tgz文件;一些make变量具有文件:=…
以避免这种情况,以提高效率和/或正确性。1)
如果FILES
应该是一个shell变量,您可以设置它,但需要在shell ese中进行设置,不带空格,并加引号:
all:
FILES="$(shell ls)"
但是,每一行都由一个单独的shell运行,因此此变量将无法保留到下一行,因此您必须立即使用它:
FILES="$(shell ls)"; echo $$FILES
这有点傻,因为shell首先会为您展开*
(和其他shell glob表达式),所以您可以:
echo *
作为您的shell命令
最后,作为一般规则(不适用于本例):如注释中所述,使用ls
的输出并不完全可靠(某些细节取决于文件名,有时甚至取决于ls
的版本;ls
的某些版本在某些情况下试图清理输出)。因此,如前所述,如果您使用GNU make,您可以使用$(通配符)
和$(subst…
来完成make
本身内部的所有工作(避免任何“文件名中的奇怪字符”问题)。(在sh
脚本(包括makefiles的配方部分)中,另一种方法是使用find…-print0 | xargs-0
避免被空格、换行符、控制字符等绊倒。)
一,。我还没有找到POSIX文档的快速参考链接,也不知道哪个
make
变体支持:=
赋值,尽管GNU make现在支持:=
赋值,其含义与:=
相同,也就是说,现在就通过扩展来完成赋值
请注意,
VAR:=$(shell命令args…
也可以拼写为VAR!=命令参数…
在几个make
变体中,包括据我所知的所有现代GNU和BSD变体。这些其他变体没有$(shell)
,因此使用VAR!=命令args…
在更短的长度和更多的变体方面都具有优势。此外,除了torek的答案之外,还有一点很突出:您使用的是一个延迟计算的宏赋值
如果您使用的是GNU Make,请使用:=
赋值,而不是=
。此赋值使右侧立即展开,并存储在左侧变量中
FILES := $(shell ...) # expand now; FILES is now the result of $(shell ...)
FILES = $(shell ...) # expand later: FILES holds the syntax $(shell ...)
如果使用
=
赋值,则意味着每次出现$(文件)
都将扩展$(shell…
语法,从而调用shell命令。这会使您的工作运行变慢,甚至会产生一些令人惊讶的后果。谢谢。我想使用一个复杂的命令(ls
withsed
和cut,例如),然后在rsync和其他命令中使用结果。我必须一遍又一遍地重复这个冗长的命令吗?我不能将结果存储在一个内部Make变量中吗?Gnu Make可能有一种方法可以做到这一点,但我从来没有使用过它,我们使用的所有极其复杂的makefile都只使用shell变量和在每行末尾根据需要使用“\”构建的大型单行shell命令。(无法使代码编码与反斜杠序列一起工作,嗯)可能类似于:FILE=$(shell ls*.c | sed-e“s^fun^bun^g”)
@William:make
可以在不使用shell的情况下实现:FILE=$(subst-fun,bun,$(通配符*.c))
。我想指出的是,尽管在这种情况下,它似乎不是很重要,但您不应该自动解析ls的输出。ls的目的是向人类显示信息,而不是用脚本链接。更多信息:如果“make”没有提供适当的通配符扩展,“find”比“ls”更好。现在我们有了列表,如何迭代列表中的每个项目并对其执行命令?例如build或test?@anon58192932执行命令的特定迭代通常在构建配方中的shell语法片段中完成,因此它发生在shell中,而不是在make:中,用于x in$(文件);do命令$$x;完成
。注意折叠的$
将单个$
传递给shell。此外,外壳碎片是一个衬里;要编写多行shell代码,可以使用反斜杠延续,该延续由make
本身处理并折叠成一行。这意味着分隔分号的shell命令是必需的。
echo *
FILES := $(shell ...) # expand now; FILES is now the result of $(shell ...)
FILES = $(shell ...) # expand later: FILES holds the syntax $(shell ...)