Bash 如何在Makefile中使用shell命令

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) 当然,这意

我试图在其他命令(例如echo、rsync)中使用
ls
的结果:

我尝试过使用
echo$$FILES
echo${FILES}
echo$(FILES)
,但运气不佳。

使用了:

FILES = $(shell ls)
all
下面缩进,就像那样,这是一个构建命令。因此,这将展开
$(shell ls)
,然后尝试运行命令
文件…

如果
文件
应该是
make
变量,则需要在配方部分之外分配这些变量,例如:

FILES = $(shell ls)
all:
        echo $(FILES)
当然,这意味着在运行创建.tgz文件的任何命令之前,
FILES
将被设置为“output from
ls
”。(尽管变量每次都会重新展开,因此最终它将包含.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
with
sed
和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 ...)