试图做到。
help:
@echo "you must $(call red_text,clean)"
其中red_text被定义为
red_text = $(shell tput setaf 1; echo -n "$1"; tput sgr0)
这将打印 "you must clean",其中 "clean "一词被打印成红色。
问题是当make的输出是管道式的(例如,到少)。在这种情况下,我不应该使用颜色,而是打印1美元。
我需要更新 red_text
来处理这个案子。为此,我想我可以使用类似 $(shell [ -t 1 ] ..)
但问题是 stdout 的 $(shell)
绝不是终端。
我如何才能改变 red
办理时 stdout 是不对终端?
的精神,在这里打印出 "你必须清洁",其中字"..."。完美不是在没有任何东西可以增加的时候达到的,而是在没有任何东西可以拿走的时候达到的(安托万-德-圣埃克苏佩里)。,解题方法是 不在第一时间使用颜色! 真的吗?它 烂 有固有的问题。你对终端做了一些假设,而这些假设对于某些可怜的用户来说,在某一天会是错误的。你遇到了这个交互式终端的问题。你把时间花在解决一个问题上,而这个问题本可以更好地花在编程酷功能上,而不是花在 养眼. 你取悦了错误的人群,即色度上瘾者,而忽视了色度上有问题的人,如红绿盲用户(其中有比你我估计更多的人)。
if test -t 1
then
echo terminal
else
echo file
fi
正如你所指出的,没有办法从以下方面进行测试 $(shell ...)
无论输出的是标准终端还是管道文件。然而,我们可以做一些事情,每件事情都有自己的proscons。
在自定义中检测TTY make
脚本
我们只需写一个简单的shell脚本,拦截对原生的 make
,检测到TTY,并适当地定义一个变量。这种方案的主要优点是
echo
, $(info ...)
和一样。$(shell ...)
命令。ifdef IS_TTY
# DO NOT ADD TRAILING COMMENTS OR THIS WILL FAIL BECAUSE OF TRAILING SPACES
ESC := $(shell printf '\e')
R := $(ESC)[31m
Z := $(ESC)[0;0m
endif
$(info [info ] $Rred$Z black)
$(shell echo >&2 "[shell ] $Rred$Z black")
if_fancy:
@echo "[recipe] $Rred$Z black"
自定义make脚本添加路径的例子(例如:) /usr/local/bin/make
):
#! /bin/bash
[ -t 1 ] && IS_TTY=1 || IS_TTY=0
exec /usr/bin/make IS_TTY=$IS_TTY "$@"
这个方法在所有这些情况下都提供了预期的输出结果。
make # Colored
make >&2 # Colored
make | cat # NOT colored
make >tmp && cat tmp # NOT colored
在配方中检测并递归调用Makefile。
在某些情况下,可能无法拦截调用make或用自定义脚本替换。在这个解决方案中,我们通过在第一次传递中检测到TTY,然后用适当的变量集递归调用相同的Makefile来解决这个限制。
ifndef IS_TTY
.SILENT:
%:
@[ -t 1 ] && IS_TTY=1 || IS_TTY=0; $(MAKE) IS_TTY=$$IS_TTY "$@"
xyz:
@[ -t 1 ] && IS_TTY=1 || IS_TTY=0; $(MAKE) IS_TTY=$$IS_TTY
else
ifeq ($(IS_TTY),1)
# DO NOT ADD TRAILING COMMENTS OR THIS WILL FAIL BECAUSE OF TRAILING SPACES
ESC := $(shell printf '\e')
R := $(ESC)[31m
Z := $(ESC)[0;0m
endif
$(info [info ] $Rred$Z black)
$(shell echo >&2 "[shell ] $Rred$Z black")
recursive:
@echo "[recipe] $Rred$Z black"
endif
这种方法的缺点是,它在Makefile中增加了不少垃圾。处理递归的问题可能很棘手。在上面的例子中,我只应用了一些基本的递归机制,这些机制应该在 make
是在有无目标的情况下被调用的,它也应该传播变量。扩展这将是另一个问题的主题;-)
剥离每个echo的转义序列
我们在每条echo命令中测试输出是否是TTY,如果不是,我们将转义序列剥离(使用 https:/superuser.comquestions380772removing-ansi-color-code-from-text-stream。). 为了减少行内的垃圾信息,我们使用了一个make变量 $(STRIPESC)
. 解决方法很简单,但它只适用于 echo
命令,并在每个回声处产生一个额外的进程。它还需要编辑每个有回音的配方。
# DO NOT ADD TRAILING COMMENTS OR THIS WILL FAIL BECAUSE OF TRAILING SPACES
ESC := $(shell printf '\e')
R := $(ESC)[31m
Z := $(ESC)[0;0m
STRIPESC:=( [ -t 1 ] && cat || sed 's/\x1b\[[0-9;]*m//g' )
# $(info ...) not supported
# $(shell echo >&2 ...) not supported
if_tty:
@echo "[recipe] $Rred$Z black" | $(STRIPESC)
使用外部echo命令来删除转义序列。
这与上面的解决方案类似,只是语法更轻巧一些。proscons是一样的。另外,在下面的例子中,我在makefile中自己生成了外部echo。在标准的构建中,你会在某个标准路径中提供这个命令作为外部工具。
# DO NOT ADD TRAILING COMMENTS OR THIS WILL FAIL BECAUSE OF TRAILING SPACES
ESC := $(shell printf '\e')
R := $(ESC)[31m
Z := $(ESC)[0;0m
$(shell echo "#! /bin/bash" > echotty)
$(shell echo '[ -t 1 ] && echo "$$@" || echo "$$@" | sed "s/\x1b\[[0-9;]*m//g"' >> echotty)
$(shell chmod a+x echotty)
# $(info ...)
# $(shell echo >&2 ...)
.PHONY: echotty
echotty:
@./echotty "[recipe] $Rred$Z black"