6

I have a makefile, with a test suite target, like so:

rcheck:
        foo

This shows the output from the foo command on stdout, and returns an exit code from foo which is handled by make as normal.

I want to add something to this target, to parse foo's output without affecting the existing behaviour - that is:

  1. foo's stdout/stderr should be displayed on stdout/stderr, as before
  2. the final outcome of the rcheck target, as far as Make is concerned, is whatever foo's exit code was
  3. stdout from foo should be passed to a second command, bar, somehow. bar's exit code doesn't matter, and bar should not output anything to stdout or stderr in addition to 1. above (unless the solution means bar handles 1. itself)

What is the neatest solution here?

2

If you're not worried about the timing of data passing from foo to bar, and you're okay with a tempfile which will need to be handled in your clean target, then simply:

rcheck:
        foo | tee sometempfile
        -bar < sometempfile >/dev/null 2>/dev/null

If on the other hand you care a lot about timing then you could make bar repeat its input to stdout and try something like:

rcheck:
        -(foo; echo $$? > sometempfile) | bar
        exit $(cat sometempfile)

I'm sure there'll be cleaner ways, but the above came to mind. (Note, both are untested)

  • If foo fails, make rcheck should fail. The first part of your answer doesn't handle that, does it? – Scott Feb 12 '15 at 11:46
  • I used your second proposal, although it's $$() not $() (the latter is expanded by Make as a variable) – directhex Feb 12 '15 at 15:33
1

If you're using a shell that supports the pipefail option (bash, ksh, and zsh do), you could do it this way:

rcheck:
    set -o pipefail; foo | tee /dev/stderr | { bar >/dev/null 2>&1; true; }

My ksh manpage documents that option as:

pipefail
      A pipeline will not complete until all components of the pipeline have
      completed, and the return value will be the value of the last non-zero
      command to fail or zero if no command has failed.

As opposed to the default behavior:

The exit status of a pipeline is the exit status of the last command
unless the pipefail option is enabled.
  • @Gilles, thanks for the edit - I missed the requirement that the original text be displayed; I was picturing a filter program that manipulated the text before it was displayed. – godlygeek Feb 11 '15 at 22:40
  • Since we're piping foo's stdout, shouldn't the tee be writing to /dev/stdout? – Scott Feb 12 '15 at 11:48
  • @Scott, /dev/stdout is getting a copy of foo's output without us doing anything. We add tee to the pipeline so that foo's output gets written to both /dev/stdout (which will become input for bar), and delivered unchanged to /dev/stderr (which is still wired to the terminal). – godlygeek Feb 12 '15 at 19:47
  • OK, I understand why … | tee /dev/stdout | … is a bad idea -- because I figured it out; I'm not sure whether I would have gotten it from your comment if I hadn't figured it out on my own first. The reason is that, when tee opens /dev/stdout, it refers to tee's stdout, which is the pipe to bar. My point is that if the user says make rcheck > make.out, then foo's stdout goes to the terminal when it should go to make.out. Therefore, this does not quite meet the OP's requirements. – Scott Feb 12 '15 at 22:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.