尝试做:
help:
@echo "you must $(call red_text,clean)"
其中red_text定义为
red_text = $(shell tput setaf 1; echo -n "$1"; tput sgr0)
打印“你必须清理”,其中“clean”字样用红色打印。
问题是当make的输出被管道传输时(例如,更少)。 在这种情况下,我不应该使用颜色,而是打印$ 1。
我需要更新red_text
来处理此案件。为此,我认为我可以使用类似$(shell [ -t 1 ] ..)
的内容,但问题是$(shell)
的 stdout 永远不会是终端。
如果 stdout 不是终端,我如何更改red
来处理这种情况?
答案 0 :(得分:1)
本着的精神,当没有什么可以补充的时候达到完美,但是当没有什么可以带走的时候(Antoine de Saint Exupery),通过来解决问题首先使用颜色!真的。 糟透了有固有的问题。你可以假设一些糟糕的用户会在某些好日子里对终端造成错误。您遇到此交互式终端问题。你花时间解决一个问题,可以更好地编写酷炫功能而不是 eye candy 。你喜欢错误的一群人,即色情上瘾,而忽视了色彩挑战的人,比如红色/绿色盲人用户(其中有超过你和我的估计)。
答案 1 :(得分:0)
if test -t 1
then
echo terminal
else
echo file
fi
答案 2 :(得分:0)
正如您所指出的那样,无法通过$(shell ...)
测试输出是标准终端还是管道/文件。但是,我们可以做一些事情,每件事都有自己的优点/缺点。
在自定义make
脚本中检测TTY
我们只需要编写一个简单的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
在某些情况下,可能无法截获调用以使用自定义脚本或将其替换为自定义脚本。在此解决方案中,我们通过首先检测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命令中测试输出是否为TTY,如果不是,则剥离转义序列(使用https://superuser.com/questions/380772/removing-ansi-color-codes-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命令删除转义序列
与上面的解决方案相似,除了语法更轻巧。优点/缺点是相同的。另外,在下面的示例中,我在makefile本身中生成了外部回显。在标准构建中,您将在某些标准路径中将此命令作为外部工具提供。
# 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"