tags:

views:

369

answers:

5

I use a Makefile (with GNU make running under Linux) to automate my grunt work when refactoring a Python script. The script creates an output file, and I want to make sure that the output file remains unchanged in face of my refactorings.

However, I found no way to get the status code of a command to affect a subsequent shell if command.

The following rule illustrates the problem:

check-cond-codes:
    diff report2008_4.csv report2008_4.csv-save-for-regression-testing; echo no differences: =$$!=
    diff -q poalim report2008_4.csv; echo differences: =$$!=

The first 'diff' compares two equal files, and the second one compares two different files. The output is:

diff report2008_4.csv report2008_4.csv-save-for-regression-testing; echo no differences: =$!=
no differences: ==
diff -q poalim report2008_4.csv; echo differences: =$!=
Files poalim and report2008_4.csv differ
differences: ==

So obviously '$$!' is the wrong variable to capture the status code of 'diff'. Even using SHELL := /bin/bash at beginning of the Makefile did not solve the problem.

A variable returning the value, which I need, would (if it exists at all) be used in an 'if' command in the real rule.

The alternative of creating a small ad-hoc shell script in lieu of writing all commands inline in the Makefile is undesirable, but I'll use it as a last resort.

Related:

A: 

Use '$$?' instead of '$$!' (thanks to 4th answer of http://stackoverflow.com/questions/90418/exit-shell-script-based-on-process-exit-code)

Omer Zak
A: 

The bash variable is $?, but why do you want to print out the status code anyway?

David Zaslavsky
A: 

Try `\$?' I think the $$ is being interpreted by the makefile

Charlie Martin
+1  A: 

Don't forget that each of your commands is being run in separate subshells.

That's why you quite often see something like:

my_target:
    do something \
    do something else \
    do last thing.

And when debugging, don't forget the every helpful -n option which will print the commands but not execute them and the -p option which will show you the complete make environment including where the various bits and pieces have been set.

HTH

cheers,

Rob Wells
+2  A: 

I think you're looking for the $? shell variable, which gives the exit code of the previous command. For example:

$ diff foo.txt foo.txt
$ echo $?
0

To use this in your makefile, you would have to escape the $, as in $$?:

all:
    diff foo.txt foo.txt ; if [ $$? -eq 0 ] ; then echo "no differences" ; fi

Do note that each command in your rule body in make is run in a separate subshell. For example, the following will not work:

all:
    diff foo.txt foo.txt
    if [ $$? -eq 0 ] ; then echo "no differences" ; fi

Because the diff and the if commands are executed in different shell processes. If you want to use the output status from the command, you must do so in the context of the same shell, as in my previous example.

Hope this helps,

Eric Melski

Eric Melski