如何用Make工具保留相同前缀的最后一个字符串?
Makefile 键值对去重(保留最后出现项)
需求
给定如下Makefile变量内容:
FILES=APPLE=A PHOTO=P APPALE=APP NUMBER=N APPALE=APPL APPALE=APPLE LARGE=L PHOTO=PHO
需要处理后得到:
FILES=NUMBER=N APPALE=APPLE LARGE=L PHOTO=PHO
核心要求:对空格分隔的KEY=VALUE格式键值对,每个KEY仅保留最后一次出现的完整键值对。
现有尝试代码
你尝试定义了uniq函数,但未达到预期效果:
define uniq $(eval _set :=)\ $(strip $(foreach w,$(1), $(eval _first := $(word 1,$(subst $(2),$(space),$(w))))\ $(if $(filter $(_set ),$(_first)),$(w),\ $(eval _set += $(_first))))\ $(eval _set :=)\ $(eval _first:=) endef
问题分析
现有函数的逻辑是试图保留首次出现的键值对,但实现本身存在逻辑漏洞,且完全不符合“保留最后出现项”的需求。
解决方案
要实现保留每个键的最后出现项,可以通过以下步骤:
- 提取所有键值对的键并去重;
- 对每个去重后的键,找到其在原字符串中最后一次出现的完整键值对;
- 拼接这些结果得到最终字符串。
以下是可行的Makefile实现:
# 提取键值对的键(等号左侧内容) get_key = $(word 1,$(subst =, ,$1)) # 去重并保留最后出现的键值对 uniq_last = $(strip $(foreach key,$(sort $(foreach kv,$(1),$(call get_key,$(kv)))),\ $(lastword $(filter $(key)=%,$(1)))\ )) # 测试示例 ORIGINAL_CONTENT := APPLE=A PHOTO=P APPALE=APP NUMBER=N APPALE=APPL APPALE=APPLE LARGE=L PHOTO=PHO FILES := $(call uniq_last,$(ORIGINAL_CONTENT)) # 验证输出 all: @echo "原始内容: $(ORIGINAL_CONTENT)" @echo "处理后结果: $(FILES)"
代码说明
get_key:将键值对按=拆分,提取等号左侧的键;uniq_last:- 遍历所有键值对提取键,用
sort去重得到唯一键列表; - 对每个唯一键,用
lastword $(filter $(key)=%,$(1))定位原字符串中该键最后一次出现的完整键值对; - 用
strip去除多余空格,拼接所有结果。
- 遍历所有键值对提取键,用
执行make all后,输出为:
原始内容: APPLE=A PHOTO=P APPALE=APP NUMBER=N APPALE=APPL APPALE=APPLE LARGE=L PHOTO=PHO 处理后结果: APPLE=A NUMBER=N APPALE=APPLE LARGE=L PHOTO=PHO
(注:若示例中期望结果缺少APPLE=A是笔误,上述代码会保留所有唯一出现的键值对;若需排除特定键,可在函数中添加额外过滤逻辑。)
内容的提问来源于stack exchange,提问作者Y2go
相关产品推荐
相关产品推荐

