如何判断makefile是否从交互式shell中运行?

10

我有一个Makefile,其中运行的命令可能需要一段时间。如果从交互式shell启动构建,则希望这些命令是冗长的,但如果不是(特别是通过cron),则要更加安静。类似下面的内容(伪代码):

foo_opts = -a -b -c
if (make was invoked from an interactive shell):
    foo_opts += --verbose

all: bar baz
    foo $(foo_opts)

这是GNU make。如果我正在做的具体事情很重要,我可以编辑问题。

5个回答

13

这并不严格确定它是从交互式 shell 调用还是非交互式 shell 调用,但对于将输出重定向到文件的 cron 作业,这个问题的答案与如何检测我的 shell 脚本是否通过管道运行?相同:

if [ -t 0 ]
then
    # input is from a terminal
fi

编辑: 要在Makefile中(GNU make)使用此方法设置变量:

INTERACTIVE:=$(shell [ -t 0 ] && echo 1)

ifdef INTERACTIVE
# is a terminal
else
# cron job
endif

通常情况下,这是检查程序是否连接到终端的最可靠方法;很少有人运行“make </dev/null”。 - Jonathan Leffler

4

http://www.faqs.org/faqs/unix-faq/faq/part5/section-5.html

5.5) 如何判断是否正在运行交互式shell?

  In the C shell category, look for the variable $prompt.

  In the Bourne shell category, you can look for the variable $PS1,
  however, it is better to check the variable $-.  If $- contains
  an 'i', the shell is interactive.  Test like so:

      case $- in
      *i*)    # do things for interactive shell
              ;;
      *)      # do things for non-interactive shell
              ;;
      esac

3
很抱歉打击你的兴致,但这告诉你的是你正在运行的shell是否是交互式的,但是在makefile中,无论你运行什么样的shell,它都会声称自己是非交互式的,即使make是从交互式shell中运行的。证明:makefile包含'all:;echo "Shell: $$-"',运行'make'将不会在输出中包含'i'。(在我的Mac上,我从'make'得到'hBc',而从我的交互式shell得到'himBH'。) - Jonathan Leffler
嗯...也许OP可以在调用make的shell中检查交互式,并设置一个环境变量,该变量可以在makefile中捕获。 - Naveen
一个环境变量有点能用,但并不是很令人满意。 - Jonathan Leffler

4

我认为你不太容易找到答案。我建议采用另一种策略,可能是通过抑制cron作业的冗长输出来实现。我会尝试使用以下这个makefile:

VERBOSE = --verbose

foo_opts = -a -b -c ${VERBOSE}

all: bar baz
    foo $(foo_opts)

然后,在cron作业中指定以下内容:
make VERBOSE=

这个命令行中的VERBOSE规范覆盖了makefile中的规范(且不能被makefile更改)。这样,您设置一次并多次使用的专门任务(cron job)将在没有冗长输出的情况下完成;建立通用任务时将会有冗长输出(除非您选择在命令行上覆盖冗长性)。这种技术的一个小优点是它适用于任何变体的make,不依赖于GNU Make设施。

0

我不太确定 "am interactive" 是什么意思。你是指如果有一个有效的 /dev/tty 吗?如果是这样,那么你可以检查一下。但是,我们大多数人会在标准输入上检查 isatty,因为它回答了我们想知道的问题:是否有人在那里输入内容。


问题在于你希望子进程知道父进程是否是交互式的,但是这种方式行不通,因为它返回的是在子进程中运行时子进程的状态。 - Dennis Williamson

0

仅供参考:您还可以查看我关于在Makefile内部检测STDOUT重定向的相关讨论

我相信这对本问题的读者会有所帮助 - 执行摘要:

-include piped.mk

all:    piped.mk
ifeq ($(PIPED),1)
    @echo Output of make is piped because PIPED is ${PIPED}
else
    @echo Output of make is NOT piped because PIPED is ${PIPED}
endif
    @rm -f piped.mk

piped.mk:
    @[ -t 1 ] && PIPED=0 || PIPED=1 ; echo "PIPED=$${PIPED}" > piped.mk

$ make
Output of make is NOT piped because PIPED is 0

$ make | more
Output of make is piped because PIPED is 1

在我的回答中,我解释了为什么[-t 1]必须在操作中而不是变量赋值中进行(如此处推荐的答案),以及关于重新评估生成的Makefile(即上面的piped.mk)的各种陷阱。
这个问题中的术语“交互式”似乎意味着重定向STDIN...在这种情况下,在我的上面的代码中用[ -t 0 ]替换[ -t 1 ]应该可以直接使用。
希望这可以帮助到您。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接