How to see if script was sucessfully run in bash script - bash

i have this code in my script :
check() {
if [ $? -eq 0 ]
then
DATA=`date +%Y%m%d_%H.%M.%S`
echo "O script $DATA Executou com sucesso" >>$log
else
DATA=`date +%Y%m%d_%H.%M.%S`
echo "O script $DATA Executou com erro"; >>$log
fi
}
but i want to put it in another script and when i execute in crontab once every 15 minutes. I want to check if the script executed successfully or not.
My question is in this first if section, how can I put the script ex3.sh for example
if script ex3.sh sucess
then
DATA=`date +%Y%m%d_%H.%M.%S`
echo "O script $DATA Executou com sucesso" >>$log
else
DATA=`date +%Y%m%d_%H.%M.%S`
echo "O script $DATA Executou com erro"; >>$log
fi
}

First to the terminology: What you show in your example (check) is not a script, but a function. It becomes a script, if you would add an actual invocation to check.
But to your proper question: You need to define somehow to the caller, whether or not you are successful. This can be done by havin your function return an exit code. This is done using the return statement. The convention is tor return 0 for success, and something between 1 and 127 for failure.
Hence, if you detect an error, do a
return 1
in your script. If everything goes well, exit it by
return 0
If you keep to this convention, you can indeed make use of the if statement you had in mind:
if check ARGUMENTS
then
.... # check function successful
else
.... # check function not successful
fi
The same principle does not only apply to functions, but also to scripts, with the main difference that with scripts, you signal the exit code not with return, but with an exit statement, i.e.
exit 0 # Success
exit 1 # Failure

Related

How to make the sh script return an error code from the executed command?

I wrote a simple script which will prompt pppd to work. I have read in the pppd documentation that it can return an exit code in the range 1-20. I would like my script to return the value of pppd if it is not 0. I tried this way but unfortunately it failed.
myscript.sh:
#!/bin/sh
exec pppd call ${#:-provider}
if [ $? !-eq 0 ]
then
exit $?
fi
How could i get the exit code from pppd?
Just do:
#!/bin/sh
pppd call "${#:-provider}" || exit
...
or
if pppd call "${#:-provider}"; then : ; else exit; fi
If pppd fails, the script will exit and the value it returns will be that returned by pppd. (You could explicitly write exit $?, but that is the default value returned by exit when no argument is given and is not necessary.) If pppd succeeds, the script will continue.
The problem with your script (other than the ill-advised usage of exec, which I will mostly ignore) is that calling [ $? -ne 0 ] resets $?. You could re-write your script as:
#!/bin/sh
pppd call "${#:-provider}"
save_val=$?
if ! [ $save_val -eq 0 ]
then
exit $save_val
fi
but that seems excessively verbose.
Note that in your original script, you would get an error on the line if [ $? !-eq 0 ], since !-eq is not a valid operator. However, you never see that error because your early invocation of exec makes it so that line is never executed.

How to get the exit code from the source script

I have two scripts main script and sub script and I called the subscript using source script, if the specified package is not installed then it should return exit code 1.
If I run the main script by using bash main.sh I am unable to get the subScriptExitCode from the main script
main script
source "sub.sh"
subScriptExitCode=$?
log "subScript ExitCode: $subScriptExitCode"
if [ $subScriptExitCode -ne 0 ]; then
exit $subScriptExitCode
fi
sub script
type -p <package>
subScriptExitCode=$?
if [ $subScriptExitCode -ne 0 ]; then
exit 1
fi
When a file is sourced, don't use exit, as this will terminate the whole execution. Instead, use return in sub.sh :
return [n]
Causes a function to exit with the return value specified
by n. If used outside a function, but during execution of a script
by the . (source) command, it causes the shell to stop executing that
script and return either n or the exit status of the last command
executed within the script as the exit status of the script. If used
outside a function and not during execution of a script by ., the
return status is false.
sub.sh
type -p <package>
subScriptExitCode="$?"
if [ "$subScriptExitCode" -ne 0 ]; then
return 1
fi
Instead of sourcing the sub script run it as below and check the return code
Main.sh
sh sub.sh
subScriptExitCode=$?
log "subScript ExitCode: $subScriptExitCode"
if [ $subScriptExitCode -ne 0 ]; then
exit $subScriptExitCode
fi
If you have a look at the manual of Bash, then you read
source filename [arguments]:
Read and execute commands from filename in the current shell environment and return the exit status of the last command executed from filename. If filename does not contain ...
source: man bash
These are two very important properties which are related to your problem:
If your sub_script encounters a subScriptExitCode which is different from zero. It will terminate the main_script instantaneously due to the exit statement.
The main_script will set subScriptExitCode to the exit state of the if-statement. This is zero in case subScriuptExitCode of sub_script equals 0.
if list; then list; [ elif list; then list; ] ... [ else list; ] fi: ... The exit status is the exit status of the last command executed, or zero if no condition tested true.
source: man bash
A possible way to solve your problem, making use only of the properties of source would be:
sub_script:
type -p <package>
[ $? -eq 0 ]
Here, the test command will exit with the state 0 if type p <package> terminated with zero, otherwise the test-command will exit with state 1. This state is then picked up in your main_source as $?. However, since type -p can only return 0 or 1, you can just get rid of the test and reduce sub_script to:
type -p <package>
type [-aftpP] name [name ...]: ... type returns true if all of the arguments are found, false if any are not found.
[source: man bash]

How to create efficient error checking in Bash script?

To check the exit code of command in Bash the following logic is used:
if [ $? -ne 0 ]
then
echo "Error occurred"
return 1
fi
My problem is that adding this after every command makes the script very long with multiple copies of the same thing, and very hard to maintain.
The best thing here would be a function, that would be called from all the locations the the exit code needs to be checked. The problem is that the exit command can not be used, because it will kill current process (current Bash session will be killed), so only the return command can be used. But when using the return command, in a called function, the calling function must still check the exit code, and were back to the same problem.
Is there any thing like MACRO in Bash or any other way to the error checking more efficient?
Instead of this:
somecommand
if [ $? -ne 0 ]
then
echo "Error occurred"
return 1
fi
You don't need to write conditions on the $? variable,
you can use the command itself in if statements:
if ! somecommand
then
echo "Error occurred"
return 1
fi
Another alternative is to create a helper function to encapsulate the action on error, and use the || operator after the command to call the function and then return 1 after:
error() {
echo "Error occurred"
}
somecommand || { error; return 1; }
Finally, if you don't really need return 1 and you don't mind to exit the script in case of failure, then you can exit 1 inside the helper function and then the caller code can become more compact:
fatal() {
echo "Error occurred"
exit 1
}
somecommand || fatal

How to exit a bash function that expects a return

I'm not completely clear on the how/why bash's exit keyword is inconsistant when calling a function that expects a return vs. not expecting a return.
For instance, in the following repro:
#!/bin/bash
exitfunc()
{
echo "Flag 1"
exit
}
exitfunc
echo "We should never see this."
We see the output:
$ ./z.bash
Flag 1
However in this slight modification:
#!/bin/bash
exitfunc()
{
echo "Flag 1"
exit
}
foo=exitfunc
echo "We should never see this."
The output shows that the function clearly does not exit the shell.
$ ./z.bash
We should never see this.
It seems that the Flag 1 in the second version is the value stored in foo, possibly to store an error code. My question is, why does exit have this behavior in a function called in this way? Does it open a new shell when a function expects a return? How is one supposed to properly exit one of these functions? Do I just need to check the output value of foo and include exit catchers all the way up the call stack?
Thanks.
When you do foo=exitfunc, you are assigning a string exitfunc to the variable foo, not executing a function. In order to execute the function, you should do foo=$(exitfunc) instead. Then the variable foo will contain the output of the function, "Flag 1". This is known as a command substitution.
The call to exit terminates the subshell within which the function has been executed, not the shell which it was called from. In order to exit the host shell, you can do something like this:
#!/bin/bash
exitfunc()
{
echo "Flag 1"
exit 1
}
foo=$(exitfunc) || exit
echo "We never see this."
The exit status is non-zero, so the host shell exits before the last line.
The return code of the function is stored in the variable $?, so if you want to use $foo before exiting, you can do something like this:
#!/bin/bash
exitfunc()
{
echo "Flag 1"
exit 1
}
foo=$(exitfunc)
e=$?
echo "$foo"
if [ $e -ne 0 ]; then exit; fi
echo "We never see this."
Output:
Flag 1
When you call:
foo=$(exitfunc)
OR old fashioned:
foo=`exitfunc`
function exitfunc is executed in a forked sub-shell due to command substitution, hence exit only terminates the sub-shell or child shell not the current shell. Hence echo statement after foo assignment is printed since this echo is executed in current shell.

Return an exit code without closing shell

I'd like to return an exit code from a BASH script that is called within another script, but could also be called directly. It roughly looks like this:
#!/bin/bash
dq2-get $1
if [ $? -ne 0 ]; then
echo "ERROR: ..."
# EXIT HERE
fi
# extract, do some stuff
# ...
Now in the line EXIT HERE the script should exit and return exit code 1. The problem is that
I cannot use return, because when I forget to source the script instead of calling it, return will not exit, and the rest of the script will be executed and mess things up.
I cannot use exit, because this closes the shell.
I cannot use the nice trick kill -SIGINT $$, because this doesn't allow to return an exit code.
Is there any viable alternative that I have overlooked?
The answer to the question title (not in the body as other answers have addressed) is:
Return an exit code without closing shell
(exit 33)
If you need to have -e active and still avoid exiting the shell with a non-zero exit code, then do:
(exit 33) && true
The true command is never executed but is used to build a compound command that is not exited by the -e shell flag.
That sets the exit code without exiting the shell (nor a sourced script).
For the more complex question of exiting (with an specific exit code) either if executed or sourced:
#!/bin/bash
[ "$BASH_SOURCE" == "$0" ] &&
echo "This file is meant to be sourced, not executed" &&
exit 30
return 88
Will set an exit code of 30 (with an error message) if executed.
And an exit code of 88 if sourced.
Will exit both the execution or the sourcing without affecting the calling shell.
Use this instead of exit or return:
[ $PS1 ] && return || exit;
Works whether sourced or not.
You can use x"${BASH_SOURCE[0]}" == x"$0" to test if the script was sourced or called (false if sourced, true if called) and return or exit accordingly.
Another option is to use a function and put the return values in that and then simply either source the script (source processStatus.sh) or call the script (./processStatus.sh) . For example consider the processStatus.sh script that needs to return a value to the stopProcess.sh script but also needs to be called separately from say the command line without using source (only relevant parts included)
Eg:
check_process ()
{
if [ $1 -eq "50" ]
then
return 1
else
return 0
fi
}
and
source processStatus.sh $1
RET_VALUE=$?
if [ $RET_VALUE -ne "0" ]
then
exit 0
fi
You can use return if you use set -e in the beginning of the script.
If you just want to check if the function returned no errors, I'd rather suggest rewriting your code like this:
#!/bin/bash
set -e # exit program if encountered errors
dq2-get ()
{
# define the function here
# ...
if [ $1 -eq 0 ]
then
return 0
else
return 255
# Note that nothing will execute from this point on,
# because `return` terminates the function.
}
# ...
# lots of code ...
# ...
# Now, the test:
# This won't exit the program.
if $(dq2-get $1); then
echo "No errors, everything's fine"
else
echo "ERROR: ..."
fi
# These commands execute anyway, no matter what
# `dq2-get $1` returns (i.e. {0..255}).
# extract, do some stuff
# ...
Now, the code above won't leave the program if the function dq2-get $1 returns errors. But, implementing the function all by itself will exit the program because of the set -e. The code below describes this situation:
# The function below will stop the program and exit
# if it returns anything other than `0`
# since `set -e` means stop if encountered any errors.
$(dq2-get $1)
# These commands execute ONLY if `dq2-get $1` returns `0`
# extract, do some stuff
# ...
Thanks for the question, my case was to source a file for some setup, but end the script and skip the setup actions if certain conditions were not met.
I had hit the issue of an attempt to use exit() actually causing the closing of my terminal, and found myself here :D
After reviewing the options for the specific solution i just went with something like the below, I also think Deepaks answer is worth reviewing if this approach works in your case.
if [ -z "$REQUIRED_VAR" ]; then
echo "please check/set \$REQUIRED_VAR ..."
echo "skipping logic"
else
echo "starting logic"
doStuff()
echo "completed logic"
fi

Resources