在 shell 输出上过滤掉

filter-out on shell output

我的src目录下有四个文件夹:dir1、dir2、dir3、dir4。

PARSE_MODULES = $$(MODULES=$$(ls -l  | grep '^d' | awk '{print $}'); echo $$MODULES);
MODULES:=$(call PARSE_MODULES,src)
all:
    @echo $(MODULES)

因此,这段代码输出

dir1 dir2 dir3 dir4

现在,我在 all 规则之前添加以下两行:

X:=dir1 dir3
MODULES:=$(filter-out $(X),$(MODULES))

输出保持不变,即 filter-out 没有按预期工作。但是,如果我手动定义 MODULES,我会得到预期的输出:

MODULES:=dir1 dir2 dir3 dir4
X:=dir1 dir3
MODULES:=$(filter-out $(X),$(MODULES))

输出: dir2 dir4

为什么filter-out无法处理awk的输出?有什么办法吗?

据我了解,shell 列表 $(MODULES=$(ls -l src | grep '^d' | awk '{print }'); echo $MODULES) 在执行 all 的配方时由 shell 评估。这太晚了。试试这个,也许:

PARSE_MODULES = $(shell ls -l  | grep '^d' | awk '{print $}')
MODULES       := $(call PARSE_MODULES,src)

X             := dir1 dir3
MODULES       := $(filter-out $(X),$(MODULES))

all:
    @echo $(MODULES)

OP 版本的小幅简化:

# possibly: find -maxdepth 1
PARSE_MODULES = $(shell find  -type d -printf "%P\n")
SKIP := dir1 dir3

MODS := $(call PARSE_MODULES,src)
FLTR := $(filter-out $(SKIP), $(MODS))

all:
    @echo MODS: $(MODS)
    @echo SKIP: $(SKIP)
    @echo FLTR: $(FLTR)

输出:

MODS: dir1 dir2 dir3 dir4
SKIP: dir1 dir3
FLTR: dir2 dir4

您的问题是您使用 $$ 延迟了 PARSE_MODULES 内容的扩展,因此它被配方中的 shell 运行,不是品牌。

这个:

PARSE_MODULES = $$(MODULES=$$(ls -l  | grep '^d' | awk '{print $}'); echo $$MODULES);
MODULES:=$(call PARSE_MODULES,src)

留下包含以下文本的 MODULES 变量:

$(MODULES=$(ls -l src | grep '^d' | awk '{print }'); echo $MODULES);

然后当你在食谱中使用 $(MODULES) 时,它会像这样展开:

all:
        @echo $(MODULES=$(ls -l src | grep '^d' | awk '{print }'); echo $MODULES);

然后 shell 将 运行 $(...) 中的命令并回显结果。

当您尝试从 make 变量 MODULES 的值中过滤掉 dir1 等名称时,没有任何反应,因为 make 变量 MODULES 包含 shell 脚本本身,作为文本,它不包含执行 shell 脚本的结果。

我不确定您为什么要尝试以如此令人难以置信的令人费解的方式做事,有这么多的转义和使用难以理解的 shell 脚本。也许您的整个环境需要如此复杂的东西是有原因的,但是您可以 FAR 更轻松地使用一些基本的 make 函数来实现上面的示例:

PARSE_MODULES = $(sort $(notdir $(patsubst %/.,%,$(wildcard /*/.))))

MODULES := $(call PARSE_MODULES,src)

现在 PARSE_MODULES 由 make 而不是配方扩展,并且 filter-out 等可以正常工作。此外,它比使用 grep 和 awk 执行 shell 要简单得多。