This question already has answers here:
Automatic exit from Bash shell script on error [duplicate]
(8 answers)
Closed 6 years ago.
#Example Script
wget http://file1.com
cd /dir
wget http://file2.com
wget http://file3.com
I want to execute the bash script line by line and test the exit code ($?) of each execution and determine whether to proceed or not:
It basically means I need to add the following script below every line in the original script:
if test $? -eq 0
then
echo "No error"
else
echo "ERROR"
exit
fi
and the original script becomes:
#Example Script
wget http://file1.com
if test $? -eq 0
then
echo "No error"
else
echo "ERROR"
exit
fi
cd /dir
if test $? -eq 0
then
echo "No error"
else
echo "ERROR"
exit
fi
wget http://file2.com
if test $? -eq 0
then
echo "No error"
else
echo "ERROR"
exit
fi
wget http://file3.com
if test $? -eq 0
then
echo "No error"
else
echo "ERROR"
exit
fi
But the script becomes bloated.
Is there a better method?
One can use set -e but it's not without it's own pitfalls. Alternative one can bail out on errors:
command || exit 1
And an your if-statement can be written less verbose:
if command; then
The above is the same as:
command
if test "$?" -eq 0; then
set -e makes the script fail on non-zero exit status of any command. set +e removes the setting.
There are many ways to do that.
For example can use set in order to automatically stop on "bad" rc; simply by putting
set -e
on top of your script. Alternatively, you could write a "check_rc" function; see here for some starting points.
Or, you start with this:
check_error () {
if [ $RET == 0 ]; then
echo "DONE"
echo ""
else
echo "ERROR"
exit 1
fi
}
To be used with:
echo "some example command"
RET=$? ; check_error
As said; many ways to do this.
Best bet is to use set -e to terminate the script as soon as any non-zero return code is observed. Alternatively you can write a function to deal with error traps and call it after every command, this will reduce the if...else part and you can print any message before exiting.
trap errorsRead ERR;
function errorsRead() {
echo "Some none-zero return code observed..";
exit 1;
}
somecommand #command of your need
errorsRead # calling trap handling function
You can do this contraption:
wget http://file1.com || exit 1
This will terminate the script with error code 1 if a command returns a non-zero (failed) result.
Related
Case statement not working. Pressing Enter(empty string) not make script exit, other cases not working too. No one exit 1 commands run when it should, all cases fails when I type text specially for it.
I find out what case works, but exit 1 statement in it not exits the script. How to exit script in that place correctly?
#!/bin/bash
...
get_virtual_host() {
if [ -t 0 ]; then
read -p "Create virtualhost (= Folder name,case sensitive)" -r host
else
# same as 'read' but for GUI
host=$(zenity --forms --add-entry=Name --text='Create virtualhost (= Folder name,case sensitive)')
fi
case "$host" in
"") notify_user "Bad input: empty" ; exit 1 ;;
*"*"*) notify_user "Bad input: wildcard" ; exit 1 ;;
*[[:space:]]*) notify_user "Bad input: whitespace" ; exit 1 ;;
esac
echo "$host"
}
host=$(get_virtual_host)
Addition to clarify:
notify_user () {
echo "$1" >&2
[ -t 0 ] || if type -p notify-send >/dev/null; then notify-send "$1"; else xmessage -buttons Ok:0 -nearmouse "$1" -timeout 10; fi
}
The function is in fact written correctly. It's how it's called that's the problem.
host=$(get_virtual_host)
When you capture a command's output the command runs in a subshell. Exiting the subshell doesn't directly cause the parent shell to exit; the parent shell needs to check the subshell's exit status.
host=$(get_virtual_host) || exit
This will exit the parent if get_virtual_host fails. A bare exit without an explicit exit code forwards the existing value of $?.
I have a simple shell script which I want to set up as a periodic Jenkins job rather than a cronjob for visibility and usability for less experienced users.
Here is the script:
#!/bin/bash
outputfile=/opt/jhc/streaming/check_error_output.txt
if [ "grep -sq 'Unable' $outputfile" == "0" ]; then
echo -e "ERROR MESSAGE FOUND\n"
exit 1
else
echo -e "NO ERROR MESSAGES HAVE BEEN FOUND\n"
exit 0
fi
My script will always return "NO ERROR MESSAGES HAVE BEEN FOUND" regardless of whether or not 'Unable' is in $outputfile, what am I doing wrong?
I also need my Jenkins job to class this as a success if 'Unable' isn't found (e.g. If script returns "0" then pass, everything else is fail)
Execute the grep command and check the exit status instead:
#!/bin/bash
outputfile=/opt/jhc/streaming/check_error_output.txt
grep -sq 'Unable' $outputfile
if [ "$?" == "0" ]; then
echo -e "ERROR MESSAGE FOUND\n"
exit 1
else
echo -e "NO ERROR MESSAGES HAVE BEEN FOUND\n"
exit 0
fi
You are comparing two different strings. The outcome will always be false, i.e. the else part is taken.
Also, no need to explicitly query the status code. Do it like this:
if grep -sq 'Unable' $outputfile
then
....
else
....
fi
I am running club.sh
inside club.sh script i am running below scripts.
test1.sh
test2.sh
test3.sh
my concern is it should run one by one and if test1 fails it will not run test2.sh and if test2.sh fails it willnot run test3.sh
how can we check? can any one suggest any idea it would be very helpful.
Thanks,
Two approaches -
First, you can examine the exit code of each of your inner scripts (test1.sh, test2.sh, ...) and decide whether to continue accordingly -
$? Will return the exit code of the previous command. It will be 0 (zero) if the script exited without an error. Anything that is not 0 can be considered a failure. So you could so something like this -
./test1.sh # execute script
if [[ $? != 0 ]]; then exit; fi # check return value, exit if not 0
Alternatively, you could use the && bash operator which will only execute subsequent commands if the previous one passed -
./test1.sh && ./test2.sh && test3.sh
Only if test1.sh returns an exit code of 0 (zero) will test2.sh execute and the same goes for test3.sh.
The first approach is good if you need to do some logging or cleanup between executing your scripts, but if you are only concerned that the execution should not continue if there was a failure then the && method would be they way I recommend.
Here is a related post dealing with the meaning behind &&
The returned value of the execution of the first command/script is stored in $? so using this value you can check if your command was successfully executed.
Try this:
bash test1.sh
if [ $? -eq 0 ]; then # if script succeeded
bash test2.sh
else
echo "script failed"
fi
If you want to exit your script whenever a command fails, you just add at the beginning of your script set -e.
#!/bin/bash
set -e
echo hello
ls /root/lalala
echo world
Otherwise, you have two options.
The first one is to use &&. For instance:
echo hello && ls /some_inexistant_directory && echo world
The second one is to check the return value after each command:
#!/bin/bash
echo toto
if [ "$?" != "0" ]; then
exit 1
fi
ls /root
if [ "$?" != "0" ]; then
exit 1
fi
echo world
if [ "$?" != "0" ]; then
exit 1
fi
You just have to put the below at the begging of the script:
#!/bin/bash -e
I have a wrapper.sh script which call another script run_workflow.sh which eventually calls a workflow. I would like to handle error for run_wrklow.sh...i.e, if the workflow is executed successfully then i need to call another script run_workflow2.sh which triggers another workflow.
Here is the sample code...Please suggest me how to handle errors
wrapper.sh
sh run_workflow.sh #trigger workflow1
if [ $? -ne 0 ]; then
echo "Workflow Failed"
else
echo "Wrokflow Success"
sh run_workflow2.sh #trigger workflow2
if [ $? -ne 0 ]; then
echo "Workflow2 Failed"
else
echo "Workflow2 Success"
fi
fi
However when i try this code I'm not able to return failed status.
Here is my suggestion. You don't need to explicitly test $?, the syntax is that if is followed by a command ([ is the test command).
exit_value=1 # default failure
if sh run_workflow.sh #trigger workflow1
then
echo "Wrokflow Success"
if sh run_workflow2.sh #trigger workflow2
then
echo "Workflow2 Success"
exit_value=0
else
echo "Workflow2 Failed" >&2
fi
else
echo "Workflow Failed" >&2
fi
exit $exit_value
Note that I echo error messages to stderr (>&2). The exit command returns an error, which is an integer between 0-255. By convention we return 0 on success and 1 on error.
I also indented my code, which all experienced programmers do.
Say I have two scripts that just print back the return code from a useless subscript:
script1
(echo; exit 0)
echo $?
script2
(echo)
echo $?
Both give back 0. But is there a way to tell that the first subscript explicitly uses the exit command?
After some research I got some breakthrough. Namely you can setup an exit_handler that can tell if there was an exit call by simply examining the last command.
#! /bin/bash
exit_handler () {
ret=$?
if echo "$BASH_COMMAND" | grep -e "^exit " >> /dev/null
then
echo "it was an explicit exit"
else
echo "it was an implicit exit"
fi
exit $ret
}
trap "exit_handler" EXIT
exit 22
This will print
it was an explicit exit
Now in order to tell the parent, instead of echoing, we can rather write to a file, a named pipe or whatever.
As per noting of choroba, exit without an argument will give implicit call, which is admittedly wrong since exit (without argument) is the same as exit $?. For that reason the regex has to take that into consideration:
#! /bin/bash
exit_handler () {
ret=$?
if echo "$BASH_COMMAND" | grep -e "^exit \|^exit$" >> /dev/null
then
echo "it was an explicit exit"
else
echo "it was an implicit exit"
fi
exit $ret
}
trap "exit_handler" EXIT
exit 22