bash 如何在 Makefile 中使用 shell 命令
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10024279/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use shell commands in Makefile
提问by Adam Matan
I'm trying to use the result of ls
in other commands (e.g. echo, rsync):
我正在尝试使用ls
其他命令(例如 echo、rsync)中的结果:
all:
<Building, creating some .tgz files - removed for clarity>
FILES = $(shell ls)
echo $(FILES)
But I get:
但我得到:
make
FILES = Makefile file1.tgz file2.tgz file3.tgz
make: FILES: No such file or directory
make: *** [all] Error 1
I've tried using echo $$FILES
, echo ${FILES}
and echo $(FILES)
, with no luck.
我试过使用echo $$FILES
,echo ${FILES}
和echo $(FILES)
,但没有运气。
回答by torek
With:
和:
FILES = $(shell ls)
indented underneath all
like that, it's a build command. So this expands $(shell ls)
, then tries to run the command FILES ...
.
all
像这样在下面缩进,这是一个构建命令。所以这会展开$(shell ls)
,然后尝试运行命令FILES ...
。
If FILES
is supposed to be a make
variable, these variables need to be assigned outside the recipe portion, e.g.:
如果FILES
应该是make
变量,则需要在配方部分之外分配这些变量,例如:
FILES = $(shell ls)
all:
echo $(FILES)
Of course, that means that FILES
will be set to "output from ls
" beforerunning any of the commands that create the .tgz files. (Though as Kaz notesthe variable is re-expanded each time, so eventually it will include the .tgz files; some make variants have FILES := ...
to avoid this, for efficiency and/or correctness.1)
当然,这意味着在运行任何创建 .tgz 文件的命令之前,FILES
它将被设置为“输出ls
” 。(尽管Kaz 指出变量每次都会重新扩展,因此最终它将包含 .tgz 文件;为了效率和/或正确性,一些 make 变体必须避免这种情况。1)FILES := ...
If FILES
is supposed to be a shell variable, you can set it but you need to do it in shell-ese, with no spaces, and quoted:
如果FILES
应该是一个shell变量,你可以设置它,但你需要在shell-ese中进行,没有空格,并引用:
all:
FILES="$(shell ls)"
However, each line is run by a separate shell, so this variable will not survive to the next line, so you must then use it immediately:
然而,每一行都由一个单独的 shell 运行,所以这个变量不会保留到下一行,所以你必须立即使用它:
FILES="$(shell ls)"; echo $$FILES
This is all a bit silly since the shell will expand *
(and other shell glob expressions) for you in the first place, so you can just:
这有点傻,因为 shell 首先会*
为您扩展(和其他 shell glob 表达式),所以您可以:
echo *
as your shell command.
作为你的 shell 命令。
Finally, as a general rule (not really applicable to this example): as esperantonotes in comments, using the output from ls
is not completely reliable (some details depend on file names and sometimes even the version of ls
; some versions of ls
attempt to sanitize output in some cases). Thus, as l0b0and idelicnote, if you're using GNU make you can use $(wildcard)
and $(subst ...)
to accomplish everything inside make
itself (avoiding any "weird characters in file name" issues). (In sh
scripts, including the recipe portion of makefiles, another method is to use find ... -print0 | xargs -0
to avoid tripping over blanks, newlines, control characters, and so on.)
最后,作为一般规则(并非真正适用于本示例):正如世界语注释中的注释,使用 from 的输出ls
并不完全可靠(某些细节取决于文件名,有时甚至取决于 的版本ls
;某些版本的ls
尝试清理输出在某些情况下)。因此,正如l0b0和理想的注释,如果您使用 GNU make,您可以使用$(wildcard)
并$(subst ...)
完成其内部的所有内容make
(避免任何“文件名中的奇怪字符”问题)。(在sh
脚本中,包括 makefile 的配方部分,另一种方法是find ... -print0 | xargs -0
用来避免被空格、换行符、控制字符等绊倒。)
1The GNU Make documentation notes further that POSIX make added ::=
assignment in 2012. I have not found a quick reference link to a POSIX document for this, nor do I know off-hand which make
variants support ::=
assignment, although GNU make does today, with the same meaning as :=
, i.e., do the assignment right now with expansion.
1 GNU Make 文档进一步指出 POSIX::=
在 2012 年增加了分配。我还没有找到一个指向 POSIX 文档的快速参考链接,我也不知道哪些make
变体支持::=
赋值,尽管 GNU make 今天做了,与:=
,即,现在用扩展做赋值。
Note that VAR := $(shell command args...)
can also be spelled VAR != command args...
in several make
variants, including all modern GNU and BSD variants as far as I know. These other variants do not have $(shell)
so using VAR != command args...
is superior in both being shorter andworking in more variants.
请注意,VAR := $(shell command args...)
也可以拼写VAR != command args...
为多种make
变体,包括据我所知的所有现代 GNU 和 BSD 变体。这些其他变体没有,$(shell)
因此在更VAR != command args...
短和在更多变体中工作方面都具有优势。
回答by Kaz
Also, in addition to torek's answer: one thing that stands out is that you're using a lazily-evaluated macro assignment.
此外,除了 torek 的回答:突出的一件事是您正在使用延迟评估的宏分配。
If you're on GNU Make, use the :=
assignment instead of =
. This assignment causes the right hand side to be expanded immediately, and stored in the left hand variable.
如果您使用 GNU Make,请使用:=
赋值而不是=
. 此赋值导致右侧立即展开,并存储在左侧变量中。
FILES := $(shell ...) # expand now; FILES is now the result of $(shell ...)
FILES = $(shell ...) # expand later: FILES holds the syntax $(shell ...)
If you use the =
assignment, it means that every single occurrence of $(FILES)
will be expanding the $(shell ...)
syntax and thus invoking the shell command. This will make your make job run slower, or even have some surprising consequences.
如果您使用=
赋值,则意味着每次出现的$(FILES)
都将扩展$(shell ...)
语法并因此调用 shell 命令。这将使您的 make 作业运行得更慢,甚至会产生一些令人惊讶的后果。