fish shell evaluate make return code - shell

I'm trying to write a script in Fish that runs a Make recipe and then executes all of the resultant binaries. The problem I'm having is that I would like to have the script exit with an error code if the make command encounters an error. Whenever I try to capture Make's return value, I end up with its output log instead.
For example:
if test (make allUnitTests) -eq 0
echo "success"
else
echo "fail"
end
returns an error because "test" is seeing the build process, not the terminating condition.
I wrote the script so that I could easily make Jenkins run all my unit tests whenever I trigger a build. Since I haven't been able to get the above section of the script working correctly, I've instead instructed Jenkins to run the make command as a separate command, which does exactly what I want: halting the entire build process without executing any binaries if anything fails to compile. Thus, at this point my question is more of an academic exercise, but I would like to add building the unit test binaries into the script (and have it cleanly terminate on a build error) for the benefit of any humans who might check out the code and would like to run the unit tests.
I played a little with something like:
if test (count (make allUnitTests | grep "Stop")) -eq 0
but this has two problems:
I'm apparently piping stdout when I need to pipe stderr. (Come to think of it, if I could just check to see if anything was written to stderr, then I wouldn't need grep at all.)
Grep is swallowing all the log data piped to it, which I really want to be visible on the console.

You are misunderstanding the parentheses - these run a command substitution. What this does is capture the output of the process running in the substitution, which it will then use as arguments (separated by newlines by default) to the process outside.
This means your test will receive the full output of make.
What you instead want to do is just run if make allUnitTests without any parens, since you are just interested in the return value.
If you would like to do something between running make and checking its return value, the "$status" variable always contains the return value of the last command, so you can save that:
make allUnitTests
set -l makestatus $status
# Do something else
if test $makestatus -eq 0
# Do the if-thing
else
# Do the else-thing
end

Related

Two ways of running a command checked with if

Both of these work. The first is shorter, but I'm guessing the second is safer or better - running the command inside $()
If so, could someone explain why the second is safer, better, etc.
if my_function "something" ; then ...
if $(my_function "something"); then ...
The first is usually what you want. The first one executes the function, checks its exit status, and runs the then section if the status indicates the function succeeds.
The second (with $( )) runs the function, captures whatever your function prints to stdout, and then tries to execute that output as another command. If it doesn't output anything, nothing gets run, so the then section gets executed if your function succeeds (just like the first version). On the other hand, if it does output anything, that gets run as another command, and the then section gets run if that succeeds. If what it printed wasn't a valid command, that counts as failure.
So, the question is, does your function print a command you want executed? If so, use the second form. It not, use the first.

Detecting success or failure of cp and rm

I have a shell script that runs a bunch of commands (on OS X 10.7) as part of a build step for XCode. The script removes a bunch of files and copies a bunch of files.
The problem I have right now is that if the cp command fails, the build still 'succeeds' according to XCode, presumably because the script still returns with an exit status of 0. How can I capture the result of the cp ? I looked up the man page and it doesn't seem to return a value.
cp will return an error code (non zero) on failure, but your script probably ignores it and proceeds to the next command.
Unless you explicitly check the return code of each command in a multi-step script, then the shell will carry on.
See Aborting a shell script if any command returns a non-zero value? for how to exit a script on any error.

Exiting a program in ruby

I'm writing some code in ruby, and I want to test for the presence of a command before the launch of the program. If the command isn't installed, I want to display an error message and quit the program. So right now, I'm doing this.
puts `type -P spark &>/dev/null && continue || { echo "You must install spark"; exit 0; } `
So, everything works fine, BUT, the "exit 0" isn't, and I can't figure out why.
Do you have any idea to fix this? Or even better, is there another way to do it?
The reason you're not exiting your script is that the call to exit is within the backticks. It's exiting the subshell called to run spark, but that's not the process interpreting your ruby script.
You could check the contents of the $? variable, which returns Process:Status for the backtick command after the command has been run.
As Daniel Pittman has suggested, however, it would be easier to check that the executable was available using something like FileTest. However, you probably want to couple that with a test of the return value, in case some other, more complex, failure occurs.
The much better way to do that is:
ENV["PATH"].split(':').any? {|x| FileTest.executable? "#{x}/spark" }
Season to taste for getting the full path, or using File.join to build the path, or platform path separators, or whatever.

Getting last process' PID in Makefile

My Makefile look something like this:
setsid ./CppServer>daemon.log 2>&1 &
echo $!>daemon.pid
What I expect it to do is to store the PID of my_awesome_script in corresponding file. However there's nothing there. So where's the problem?
If your makefile really looks like this you will get an error, because I don't see any actual make syntax, just shell syntax. However, my crystal ball tells me that these two lines might be part of the recipe for a rule. If they are, you should realise how make executes recipes; for each line a separate subshell is created, in which that line's command is executed independently: your two commands don't know anything about each other's environment. If you want two commands to be executed in the same subshell, you should issue them as one line (using line continuation characters if necessary), or use make's ONESHELL directive.
The variable you're trying to use prints the pid of the last program run in the background. It is correctly written as echo $! > filename.extension. But since you are running it in the foregorund you have two choices. Run it in the background by appending an & to the end of the line ./script_to_run &, or you can have the script itself print to file the pid of the currently running process by using echo $$ > filename.extension (inside the script). Here is a link that might help you http://tldp.org/LDP/abs/html/internalvariables.html

Log invoked commands of make

Is there a way to log the commands, make invokes to compile a program? I know of the parameters -n and -p, but they either don't resolve if-conditions but just print them out. Or they don't work, when there are calls to 'make' itself in the Makefile.
This
make SHELL="sh -x -e"
will cause the shell (which make invokes to evaluate shell constructs) to print information about what it's doing, letting you see how any conditionals in shell commands are being evaluated.
The -e is necessary to ensure that errors in a Makefile target will be properly detected and a non-zero process exit code will be returned.
You could try to log execve calls with strace
strace -f -e execve make ...
Make writes each command it executes to the console, so
make 2>&1 | tee build.log
will create a log file named build.log as a side effect which contains the same stuff written to the screen. (man tee for more details.)
2>&1 combines standard output and errors into one stream. If you didn't include that, regular output would go into the log file but errors would only go to the console. (make only writes to stderr when a command returns an error code.)
If you want to suppress output entirely in favor of logging to a file, it's even simpler:
make 2>&1 > build.log
Because these just capture console output they work just fine with recursive make.
You might find what you're looking for in the annotated build logs produced by SparkBuild. That includes the commands of every rule executed in the build, whether or not "#" was used to prevent make from printing the command-line.
Your comment about if-conditions is a bit confusing though: are you talking about shell constructs, or make constructs? If you mean shell constructs, I don't think there's any way for you to get exactly what you're after except by using strace as others described. If you mean make constructs, then the output you see is the result of the resolved conditional expression.
Have you tried with the -d parameter (debug)?
Note that you can control the amount of infos with --debug instead. For instance, --debug=a (same as -d), or --debug=b to show only basic infos...

Resources