gpt4 book ai didi

linux - gnu make - 确定 stdout 是否是终端

转载 作者:太空狗 更新时间:2023-10-29 11:19:47 26 4
gpt4 key购买 nike

尝试做:

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 的输出是通过管道传输的(例如,传输到 less)。在这种情况下,我不应该使用颜色,而是打印 $1。

我需要更新 red_text来办案。为此,我想我可以使用类似 $(shell [ -t 1 ] ..) 的东西但问题是 $(shell)stdout永远不是终端。

如何更改 red处理 stdout 不是终端的情况?

最佳答案

正如您所指出的,无法从 $(shell ...) 测试输出是标准终端还是管道/文件。然而,我们可以做一些事情,每件事都有自己的优点/缺点。

在自定义 make 脚本中检测 TTY

我们只需编写一个简单的 shell 脚本来拦截对 native make 的调用,检测 TTY,并适本地定义一个变量。该解决方案的主要优点:

  • 简单,
  • 适用于echo$(info ...) 和类似的$(shell ...) 命令,
  • 食谱无需修改,
  • 每次回显都不会产生额外的进程,这在某些平台上可能非常慢(例如 Cygwin)。
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

在recipe中检测并递归调用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 处去除转义序列

我们在每个 echo 命令中测试输出是否为 TTY,如果不是,我们将去除转义序列(使用 https://superuser.com/questions/380772/removing-ansi-color-codes-from-text-stream )。为了减少线路上的垃圾邮件,我们使用了一个 make 变量 $(STRIPESC)。解决方案非常简单,但它只适用于 echo 命令,并在每次回显时产生一个额外的进程。它还需要用 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)

使用外部回显命令去除转义序列

这与上面的解决方案类似,只是语法更轻量一些。优点/缺点是相同的。此外,在下面的示例中,我在 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"

关于linux - gnu make - 确定 stdout 是否是终端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14625676/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com