Jenkins - Continue script on failure - bash

I have a freestyle Jenkins job that has a simple bash script for a build.
In the bash script, there is a for loop which sometimes returns a non-zero return code.
Thing is, Jenkins quits immediately when it happens. However, if during the run it gets a non-zero return code, the job needs to continue, and in the end mark the job as failed. (In other words, don't stop on failure but show the job failed when it's finished). (that's why I can't just append || true)
Is it possible to do? Thanks ahead!

If you set the bash option -e, (ie: #!/bin/bash -e) then the shell script will exit upon error. This is typically desired to avoid lots of testing for failures and still catching them, so many scripts have that configuration. Also, typically, this is NOT applicable inside loops if it-then-else constructs, so you should investigate what inner command you are invoking and what it is doing .. it may have an exit $? that is propagating.
If running a Jenkins execute shell step, you can add the first line #!/bin/bash +e and that may override the fail. Otherwise, try:
#!/bin/bash
FAILURE=false
set +e
for ENTRY in 1 2 3 4 5 .. N
do
command ${ENTRY}
[[ $? == 0 ]] || FAILURE=true
done
set -e
[[ ${FAILURE} == 'true' ]] && return 1
return 0

Related

Capturing exit status of a failed command in a shell script

I have a shell script with multiple commands as below
cmd-1
cmd-2
cmd-3
....
cmd-n
I want the shell script execution to continue even if there is a failure in the middle e.g cmd-3 or cmd-7. To achieve this I used set +e. This allows me to continue the execution, but I am unable to capture the exit status of the failed command (since exit status of the script is always based on the last command). Is there any way to set the status of the complete script based on last failed command.
You can achieve it like that. Not too clean way, but quite easy.
exit_code=0
cmd-1 || exit_code=$?
cmd-2 || exit_code=$?
cmd-3 || exit_code=$?
....
cmd-n || exit_code=$?
exit $exit_code
The clean way would be to split your code to functions and check result of you commands there.

error handling in shell script to stop flow execution on next line

I would like to setup a error handling on my shell script where is my invocation of script fail with error, I should be able to stop the executin and flow should nt go on next line.
Like In my main script, I am making call to below script
sh /usr/oracle/StopServer.sh
if this script fail with error, my next script on this main file should not execute.. pls help.
You can check the return value of the command execution, one way to do this is:
sh /usr/oracle/StopServer.sh
if [ $? -ne 0 ]; then
# exit or take action
fi
it should do the trick
Here you go.
sh /usr/oracle/StopServer.sh && sh my_next_line_that_only_happens_if_Stop_server_exits_without_error
For more information, the && operator in bash (and most languages) exhibits McCarthy evaluation which is basically just lazy evaluation for boolean conditionals. what this means is that for an and (&&) then the second term of the and expression will only be evaluated if the first part is true (because otherwise the result is garuanteed to be false. Similarly if we did A || B (or) B would only be executed if A were false, which means it returned with an exit code of 0 and thus failed. If you had a program that you wanted to execute if the program exited normally and another that you want to execute if it exited with a failed state (I'm going to call them normal and fail) then you could execute them like so:
sh condition.sh && sh normal.sh || sh fail.sh
EDIT:
if [ sh condition.sh ]; then
# do whatever
else
#this is what to do if it failed
fi
EDIT #2:
If you want to see what happens try running this:
if [ ls -badoption ] ; then
echo "passed "
else
echo "failed"
fi
# result follows
# zsh: parse error: condition expected: ls
# failed
it will fail as there is a bad option and failed will be run, if you had just put ls it would have echoed passed, this is where you can either exit or run the script depending on what path you take.

Best Option for resumable script

I am writing a script that executes around 10 back-end processes in sequence, depending on if the previous process was executed without any errors.
Now let's assume the scenario, in which lets say 5th process failed and script came out. But I want to code it in a way such that, when next time user runs it(after removing the error because of which script exited last time), he should be able to run from 5th process onwards and not again from 1st process.
To be more specific, assume following is the script:
Script Starts
Process1
if [ $? -eq 0 ] then
Process2
if [ $? -eq 0 ] then
Process3
if [ $? -eq 0 ] then
..
..
..
..
if [ $? -eq 0 ] then
Process10
else
exit
So here the script will exit anytime if any one of the process fails to complete with status 0. So again, if process5 fails, and user corrects the problem and restarts script, the script should start with process5 again and not process1 or at least there should be an option to user if he wants to resume the script or start it back from beginning i.e. process1.
What all possible ways we can code this kind of script, also please bear in mind, I am not allowed to use a temporary db, where I can store the status of each process.
I need to code in sh (shell script) in unix.
A simple solution would be to write stamp files:
#/bin/sh
set -e # Automatically abort if any simple command fails
if ! test -f cmd1-stamp; cmd1; fi
touch cmd1-stamp
if ! test -f cmd2-stamp; cmd2; fi
touch cmd2-stamp
When the script executes, if cmd1-stamp exists, cmd1 is not executed. Otherwise, cmd1 is executed. The script will abort if it fails. Note that it is very tempting to write test -f cmd1-stamp || cmd1, and this seems to work ( in bash ) but the shell specs state that the shell shall abort if the simple command that fails is not a part of an AND or OR list, and I suspect this is (yet another) instance of bash not conforming to the spec. (Although it doesn't seem to specify that the shell shall not abort if the failing command is part of an AND or OR list.)

Bash: How to lock also when perform an outside script

Here is my bash code:
(
flock -n -e 200 || (echo "This script is currently being run" && exit 1)
sleep 10
...Call some functions which is written in another script...
sleep 5
) 200>/tmp/blah.lockfile
I'm running the script from two shells successively and as long as the first one is at "sleep 5" all goes good, meaning that the other one doesn't start. But when the first turns to perform the code from another script (other file) the second run starts to execute.
So I have two questions here:
What should I do to prevent this script and all its "children" from run while the script OR its "child" is still running.
(I didn't find a more appropriate expression for running another script other than a "child", sorry for that :) ).
According to man page, -n causes the process to exit when it fails to gain the lock, but as far as I can see it just wait until it can run. What am I missing ?
Your problem may be fairly mundane. Namely,
false || ( exit 1 )
Does not cause the script to exit. Rather, the exit instructs the subshell to exit. So change your first line to:
flock -n -e 200 || { echo "This script is currently being run"; exit 1; } >&2

Getting the return value in "sh -e"

I'm writing a shell script with #!/bin/sh as the first line so that the script exits on the first error. There are a few lines in the file that are in the form of command || true so that the script doesn't exit right there if the command fails. However, I still want to know know the exit code of the command. How would I get the exit code without having to use set +e to temporarily disable that behavior?
Your question appears to imply set -e.
Assuming set -e:
Instead of command || true you can use command || exitCode=$?. The script will continue and the exit status of command is captured in exitCode.
$? is an internal variable that keeps the exit code of the last command.
Since || short-circuits if command succeeds, set exitCode=0 between tests or instead use: command && exitCode=0 || exitCode=$?.
But prefer to avoid set -e style scripting altogether, and instead add explicit error handling to each command in your script.
If you want to know the status of the command, then presumably you take different actions depending on its value. In which case your code should look something like:
if command; then
# do something when command succeeds
else
# do something when command fails
fi
In that case you don't need to do anything special, since the shell will not abort when command fails.
The only reasons set -e would give you any problems is if you write your code as:
command
if test $? = 1; ...
So don't do that.

Resources