简体   繁体   English

Makefile中shell命令的使用方法

[英]How to use shell commands in Makefile

I'm trying to use the result of ls in other commands (eg echo, rsync):我正在尝试在其他命令(例如 echo、rsync)中使用ls的结果:

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 $$FILESecho ${FILES}echo $(FILES) ,但没有成功。

With:和:

FILES = $(shell ls)

indented underneath all like that, it's a build command.像这样在下面缩进, all是一个构建命令。 So this expands $(shell ls) , then tries to run the command FILES... .所以这扩展$(shell ls) ,然后尝试运行命令FILES...

If FILES is supposed to be a make variable, these variables need to be assigned outside the recipe portion, eg:如果FILES应该是make变量,则需要在配方部分之外分配这些变量,例如:

FILES = $(shell ls)
all:
        echo $(FILES)

Of course, that means that FILES will be set to "output from ls " before running any of the commands that create the.tgz files.当然,这意味着在运行任何创建 .tgz 文件的命令之前FILES将被设置为“从ls输出”。 (Though as Kaz notes the 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 ) (尽管Kaz 指出变量每次都会重新扩展,因此最终它将包含 .tgz 文件;一些 make 变体具有FILES:=...以避免这种情况,以提高效率和/或正确性。1

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 esperanto notes 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).最后,作为一般规则(并非真正适用于此示例):正如世界语在评论中指出的那样,使用ls中的output并不完全可靠(一些细节取决于文件名,有时甚至取决于ls的版本;某些版本的ls尝试在某些情况下对 output 进行消毒)。 Thus, as l0b0 and idelic note, 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).因此,作为l0b0idelic注释,如果您正在使用 GNU make,则可以使用$(wildcard)$(subst...)来完成make自身内部的所有操作(避免任何“文件名中的奇怪字符”问题)。 (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.) (在sh脚本中,包括 makefile 的配方部分,另一种方法是使用find... -print0 | xargs -0来避免被空格、换行符、控制字符等绊倒。)


1 The GNU Make documentation notes further that POSIX make added ::= assignment in 2012 . 1 GNU Make 文档进一步指出 POSIX make 在 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 := , ie, do the assignment right now with expansion.我没有为此找到指向 POSIX 文档的快速参考链接,我也不知道哪些变体支持::=赋值,尽管 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.请注意, VAR:= $(shell command args...)也可以拼写为VAR.= command args...在几个make变体中,包括据我所知的所有现代 GNU 和 BSD 变体。 These other variants do not have $(shell) so using VAR.= command args... is superior in both being shorter and working in more variants.这些其他变体没有$(shell)因此使用VAR.= command args...在更短在更多变体中工作方面更胜一筹。

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 = .如果您使用的是 GNU Make,请使用:=赋值而不是= This assignment causes the right hand side to be expanded immediately, and stored in the left hand variable.此赋值导致右侧立即展开,并存储在左侧变量中。

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.如果使用=赋值,则意味着$(FILES)的每次出现都将扩展$(shell...)语法,从而调用 shell 命令。 This will make your make job run slower, or even have some surprising consequences.这将使您的 make 作业运行得更慢,甚至会产生一些令人惊讶的后果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM