繁体   English   中英

Makefile中shell命令的使用方法

[英]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 $$FILESecho ${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 进行消毒)。 因此,作为l0b0idelic注释,如果您正在使用 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.

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