Getting exit code of an expect script within same function - bash

I have the following code in a function. Is there a way to get the exit code after the expect script is run, however do a command with the exit code within the same function? I know you can you "$?" after the function is executed, however I would like to handle the exit code accordingly within the function itself.
getVersion(){
cmd="command_with_options"
mcasPassword="sample"
expect <<-EOS |& tee ${hostname}.log
#!/usr/bin/expect
set timeout $EXP_TIMEOUT
spawn sh
expect "$prompt"
send -- "$cmd\r"
expect "*assword"
send -- "$mcasPassword\r"
expect {
"*rror*" {
puts "\nAn issue was faced\n"
exit 1
}
"$prompt" {
puts "\nSuccessfully reached\n"
}
}
expect eof
exit 0
EOS
echo "Error code is as follows: $?"
#The above line isn't capturing the exit code ^
}
Any help would be highly appreciated.

Thank you #KamilCuk for posting the answer to this question:
echo "Error code is as follows: ${PIPESTATUS[0]}"

Related

How to handle non-timeout exception of a script being run with timeout?

I am running a command. In case of failure part after || would be executed. It would also be executed in case of timeout.
$ timeout 5 script.sh || { echo "Would execute if timeout or script failure"; }
How can I handle timeout error and script error separately?
$ timeout 5 script.sh ??? { echo "Timeout is fine, but this is printed only if script.sh returns an error"; }
Oguz is correct. You need to check the exit code of the timeout command. If you can review the script.sh to make sure that it doesn't return an exit code of 124, you can help reduce the risk identified by Oguz.
So, I believe the code would look like this:
$ timeout 5 script.sh || [ $? -eq 124 ] || { echo "Timeout is fine, but this is printed only if script.sh returns an error"; }

How can I stop execution of a bash script, whether or not it's invoked with "source"?

I am trying to get rid of an exit call in a bash script in order to make it sourceable.
At this moment the script contains an exit which is ok if you call the script normally, but if you source it, it will also stop the execution of the calling script which is not desired.
If I replace the exit with a return it will work well when source but it will fail with an error when is not sourced.
return: can only `return' from a function or sourced script
I am looking at a solution what would work with both cases.
You could wrap the script's code in a function which you can then return from.
__main() {
unset -f __main
...
if whatever; then
return
fi
...
}
__main "$#"
Try to return, fall back to exit if it fails.
{ retval=$?; return "$retval" 2>/dev/null || exit "$retval"; }
Tested as follows:
cat >one <<'EOF'
#!/usr/bin/env bash
echo "one starting"
source two
echo "one ending"
EOF
cat >two <<'EOF'
#!/usr/bin/env bash
echo "two starting"
echo "two attempting to exit"
{ retval=$?; return "$retval" 2>/dev/null || exit "$retval"; }
echo "two still running after attempted exit
EOF
source one
...which properly/correctly emits:
one starting
two starting
two attempting to exit
one ending
...whereas running chmod +x two; ./two emits:
two starting
two attempting to exit

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

BASH Multiple on-exit functions for different exit levels

How can I use multiple on-exit traps in bash?
say i want to run on-exit-1 on exit code 1
and on-exit-2 on exit code 2
function on-exit1 {
echo "do stuff here if code had exit status 1"
}
function on-exit2 {
echo "do stuff here if code had exit status 2"
}
.....
trap on-exit1 EXIT # <--- what do i do here to specify the exit code to trap
trap on-exit2 EXIT # <--- what do i do here to specify the exit code to trap
.....
some bashing up in here
blah...blah
exit 1 # do on-exit1
else blah blah
exit 2 # do on-exit2
else blah blah
exit N # do on-exitNth
Something like the following code sample should work :
exit_check () {
# bash variable $? contains the last function exit code
# will run the function on_exit1 if status exit is 1, on_exit2 if status exit is 2, ...
on_exit$?
}
trap exit_check EXIT
If you really want to use Traps, try this:
#!/usr/bin/env bash
function finish {
echo "exitcode: $?"
}
trap finish EXIT
read -n 1 -s exitcode
exit $exitcode
But as #123 suggested, you could just call your exit functions, no need to 'abuse' Traps here.
Try to provide working a working example next time ;).

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