如何在Makefile中使用tput实现终端全宽分隔线格式化输出?
在Makefile中用tput生成全宽分隔线的解决方法
你遇到的问题核心是Makefile的变量展开顺序和shell命令转义的问题。原命令里的$(tput cols)会被Make优先解析,而不是留给shell执行,这就导致要么拿到的是Make进程启动时的终端尺寸(甚至可能是空值),要么直接解析出错,最终输出空行。
下面是两种可行的解决方案:
方案一:动态获取当前终端宽度(推荐)
这个方法会在每次执行目标时,让shell实时获取终端宽度,适配窗口大小变化:
lineTest: @echo "$$(printf '%*s' "$${COLUMNS:-$$(tput cols)}" '' | tr ' ' –)"
关键转义解释:
$$(printf):Make会把$$解析成单个$传递给shell,所以shell实际执行的是$(printf)命令。"$${COLUMNS:-$$(tput cols)}":$${COLUMNS}:让Make传递${COLUMNS}给shell,shell会读取环境变量中的终端宽度。$$(tput cols):Make转义后,shell看到的是$(tput cols),会执行该命令获取终端宽度(当COLUMNS变量不存在时生效)。
- 双引号包裹整个命令结果:避免shell对输出内容做不必要的拆分。
如果要兼容非交互式环境(比如CI流水线,tput可能无法获取终端尺寸),可以加个默认值:
lineTest: @echo "$$(printf '%*s' "$${COLUMNS:-$$(tput cols 2>/dev/null || echo 80)}" '' | tr ' ' –)"
方案二:提前获取终端宽度(静态)
如果不需要适配窗口大小变化,可以在Makefile解析阶段就获取终端宽度,之后复用这个值:
# 在Makefile解析时获取终端宽度,仅执行一次 TERM_COLS := $(shell tput cols 2>/dev/null || echo 80) lineTest: @echo "$$(printf '%*s' "$(TERM_COLS)" '' | tr ' ' –)"
这个方法的缺点是,如果用户在Makefile解析后调整了终端窗口大小,分隔线宽度不会更新。
测试验证
保存上述Makefile后,执行make lineTest,就能看到横跨终端全宽的分隔线了。
内容的提问来源于stack exchange,提问作者Audun Olsen
相关产品推荐
相关产品推荐

