10

I have a makefile which runs commands that can take a while. I'd like those commands to be chatty if the build is initiated from an interactive shell but quieter if not (specifically, by cron). Something along the lines of (pseudocode):

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

all: bar baz
    foo $(foo_opts)

This is GNU make. If the specifics of what I'm doing matter, I can edit the question.

Reid
  • 1,999
  • 3
  • 17
  • 25

5 Answers5

13

It isn't strictly determining whether it is invoked from an interactive shell or not, but for a cron job in which the output is redirected to a file, the answer to this question would be the same as for How to detect if my shell script is running through a pipe?:

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

Edit: To use this to set a variable in a Makefile (in GNU make, that is):

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

ifdef INTERACTIVE
# is a terminal
else
# cron job
endif
Community
  • 1
  • 1
PleaseStand
  • 31,641
  • 6
  • 68
  • 95
4

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

5.5) How can I tell if I am running an interactive 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
Naveen
  • 4,456
  • 2
  • 22
  • 16
  • 3
    Sorry to rain on your parade, but that tells you whether the shell you're running was run interactively, but inside a makefile, any shell you run will claim it is being run non-interactively, even if `make` is itself run from an interactive shell. Proof: `makefile` contains '`all:;echo "Shell: $$-"`' and run 'make' and it will not include 'i' in the output. (On my Mac, I got 'hBc' from 'make' compared with 'himBH' from my interactive shell.) – Jonathan Leffler Nov 23 '10 at 00:25
  • Hmm.. maybe the OP can check for interactive in the shell that invokes make and set an environment variable that can be captured in the makefile. – Naveen Nov 23 '10 at 00:33
  • An environment variable sort-of mostly works, but isn't very satisfactory. – Jonathan Leffler Nov 23 '10 at 01:13
4

I do not think you can easily find out. I suggest adopting an alternative strategy, probably by quelling the verbose output from the cron job. I would look to do that using a makefile like this:

VERBOSE = --verbose

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

all: bar baz
    foo $(foo_opts)

Then, in the cron job, specify:

make VERBOSE=

This command-line specification of VERBOSE overrides the one in the makefile (and cannot be changed by the makefile). That way, the specialized task (cron job) that you set up once and use many times will be done without the verbose output; the general task of building will be done verbosely (unless you elect to override the verbose-ness on the command line).

One minor advantage of this technique is that it will work with any variant of make; it does not depend on any GNU Make facility.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
0

I’m not really sure what "am interactive" means. Do you mean if you have a valid /dev/tty? If so, then you could check that. Most of us check isatty on stdin, though, because it answers the questions we want to know: is there someone there to type something.

tchrist
  • 78,834
  • 30
  • 123
  • 180
  • The problem is that you want the child to know whether the parent is interactive and you can't do that this way since it returns the status of the child when run in the child. – Dennis Williamson Nov 23 '10 at 01:28
0

Just a note: you can also see the related discussion that I had about detecting redirection of STDOUT from inside a Makefile.

I believe it will be helpful to readers of this question - executive summary:

-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

In my answer there I explain why the [-t 1] has to be done in an action and not in a variable assignment (as in the recommended answer here), as well as the various pitfalls regarding re-evaluation of a generated Makefile (i.e. the piped.mk above).

The term interactive in this question seems to imply redirection of STDIN... in which case replacing [ -t 1 ] with [ -t 0 ] in my code above should work as-is.

Hope this helps.

ttsiodras
  • 10,602
  • 6
  • 55
  • 71