bash exit code out of range - bash

I'm a bit confused about these kinds of Bash exit codes.
For example:
# (exit 444)
then when I use echo command to show exit code:
# echo $?
this is gonna result it : 188
It seems that it is a result from 444-256.I know that exit codes range is 0-255.So they will count as 256 exit codes in total.
But when I use:
(exit 555)
what calculation occurs? This returns 43 as exit code.

You are experiencing the effect of 8-bit integer overflow. After 255 (all 8 bits set) comes 0 (no bits set).
So the calculation you're seeing is "exit code modulo 256".
From the Bash manual, emphasis mine:
Exit Status
The exit status of an executed command is the value returned by the waitpid system call or equivalent function. Exit statuses fall between 0 and 255, though, as explained below, the shell may use values above 125 specially. Exit statuses from shell builtins and compound commands are also limited to this range. Under certain circumstances, the shell will use special values to indicate specific failure modes.
The last part becomes important once signals come into play, which may interrupt a process and give an exit code of...
...128+n if the command is terminated by signal n...
...but that's the shell at work, not the exit command (which does not allow those values).

Related

Bash - Exit function with error message instead of return value to variable [duplicate]

What is the difference between the return and exit statement in Bash functions with respect to exit codes?
From man bash on return [n];
Causes a function to stop executing and return the value specified by n to its caller. If n is omitted, the return status is that of the last command executed in the function body.
... on exit [n]:
Cause the shell to exit with a status of n. If n is omitted, the exit status is that of the last command executed. A trap on EXIT is executed before the shell terminates.
EDIT:
As per your edit of the question, regarding exit codes, return has nothing to do with exit codes. Exit codes are intended for applications/scripts, not functions. So in this regard, the only keyword that sets the exit code of the script (the one that can be caught by the calling program using the $? shell variable) is exit.
EDIT 2:
My last statement referring exit is causing some comments. It was made to differentiate return and exit for the understanding of the OP, and in fact, at any given point of a program/shell script, exit is the only way of ending the script with an exit code to the calling process.
Every command executed in the shell produces a local "exit code": it sets the $? variable to that code, and can be used with if, && and other operators to conditionally execute other commands.
These exit codes (and the value of the $? variable) are reset by each command execution.
Incidentally, the exit code of the last command executed by the script is used as the exit code of the script itself as seen by the calling process.
Finally, functions, when called, act as shell commands with respect to exit codes. The exit code of the function (within the function) is set by using return. So when in a function return 0 is run, the function execution terminates, giving an exit code of 0.
return will cause the current function to go out of scope, while exit will cause the script to end at the point where it is called. Here is a sample program to help explain this:
#!/bin/bash
retfunc()
{
echo "this is retfunc()"
return 1
}
exitfunc()
{
echo "this is exitfunc()"
exit 1
}
retfunc
echo "We are still here"
exitfunc
echo "We will never see this"
Output
$ ./test.sh
this is retfunc()
We are still here
this is exitfunc()
I don't think anyone has really fully answered the question because they don't describe how the two are used. OK, I think we know that exit kills the script, wherever it is called and you can assign a status to it as well such as exit or exit 0 or exit 7 and so forth. This can be used to determine how the script was forced to stop if called by another script, etc. Enough on exit.
return, when called, will return the value specified to indicate the function's behavior, usually a 1 or a 0. For example:
#!/bin/bash
isdirectory() {
if [ -d "$1" ]
then
return 0
else
return 1
fi
echo "you will not see anything after the return like this text"
}
Check like this:
if isdirectory $1; then echo "is directory"; else echo "not a directory"; fi
Or like this:
isdirectory || echo "not a directory"
In this example, the test can be used to indicate if the directory was found. Notice that anything after the return will not be executed in the function. 0 is true, but false is 1 in the shell, different from other programming languages.
For more information on functions: Returning Values from Bash Functions
Note: The isdirectory function is for instructional purposes only. This should not be how you perform such an option in a real script.*
Remember, functions are internal to a script and normally return from whence they were called by using the return statement. Calling an external script is another matter entirely, and scripts usually terminate with an exit statement.
The difference "between the return and exit statement in Bash functions with respect to exit codes" is very small. Both return a status, not values per se. A status of zero indicates success, while any other status (1 to 255) indicates a failure. The return statement will return to the script from where it was called, while the exit statement will end the entire script from wherever it is encountered.
return 0 # Returns to where the function was called. $? contains 0 (success).
return 1 # Returns to where the function was called. $? contains 1 (failure).
exit 0 # Exits the script completely. $? contains 0 (success).
exit 1 # Exits the script completely. $? contains 1 (failure).
If your function simply ends without a return statement, the status of the last command executed is returned as the status code (and will be placed in $?).
Remember, return and exit give back a status code from 0 to 255, available in $?. You cannot stuff anything else into a status code (e.g., return "cat"); it will not work. But, a script can pass back 255 different reasons for failure by using status codes.
You can set variables contained in the calling script, or echo results in the function and use command substitution in the calling script; but the purpose of return and exit are to pass status codes, not values or computation results as one might expect in a programming language like C.
Sometimes, you run a script using . or source.
. a.sh
If you include an exit in the a.sh, it will not just terminate the script, but end your shell session.
If you include a return in the a.sh, it simply stops processing the script.
exit terminates the current process; with or without an exit code, consider this a system more than a program function. Note that when sourcing, exit will end the shell. However, when running, it will just exit the script.
return from a function go back to the instruction after the call, with or without a return code. return is optional and it's implicit at the end of the function. return can only be used inside a function.
I want to add that while being sourced, it's not easy to exit the script from within a function without killing the shell. I think, an example is better on a 'test' script:
#!/bin/bash
function die(){
echo ${1:=Something terrible wrong happen}
#... clean your trash
exit 1
}
[ -f /whatever/ ] || die "whatever is not available"
# Now we can proceed
echo "continue"
doing the following:
user$ ./test
Whatever is not available
user$
test -and- the shell will close.
user$ . ./test
Whatever is not available
Only test will finish and the prompt will show.
The solution is to enclose the potentially procedure in ( and ):
#!/bin/bash
function die(){
echo $(1:=Something terrible wrong happen)
#... Clean your trash
exit 1
}
( # Added
[ -f /whatever/ ] || die "whatever is not available"
# Now we can proceed
echo "continue"
) # Added
Now, in both cases only test will exit.
The OP's question:
What is the difference between the return and exit statement in BASH functions with respect to exit codes?
Firstly, some clarification is required:
A (return|exit) statement is not required to terminate execution of a (function|shell). A (function|shell) will terminate when it reaches the end of its code list, even with no (return|exit) statement.
A (return|exit) statement is not required to pass a value back from a terminated (function|shell). Every process has a built-in variable $? which always has a numeric value. It is a special variable that cannot be set like "?=1", but it is set only in special ways (see below *).
The value of $? after the last command to be executed in the (called function | sub shell) is the value that is passed back to the (function caller | parent shell). That is true whether the last command executed is ("return [n]"| "exit [n]") or plain ("return" or something else which happens to be the last command in the called function's code.
In the above bullet list, choose from "(x|y)" either always the first item or always the second item to get statements about functions and return, or shells and exit, respectively.
What is clear is that they both share common usage of the special variable $? to pass values upwards after they terminate.
* Now for the special ways that $? can be set:
When a called function terminates and returns to its caller then $? in the caller will be equal to the final value of $? in the terminated function.
When a parent shell implicitly or explicitly waits on a single sub shell and is released by termination of that sub shell, then $? in the parent shell will be equal to the final value of $? in the terminated sub shell.
Some built-in functions can modify $? depending upon their result. But some don't.
Built-in functions "return" and "exit", when followed by a numerical argument both set $? with their argument, and terminate execution.
It is worth noting that $? can be assigned a value by calling exit in a sub shell, like this:
# (exit 259)
# echo $?
3
In simple words (mainly for newbie in coding), we can say,
`return`: exits the function,
`exit()`: exits the program (called as process while running)
Also if you observed, this is very basic, but...,
`return`: is the keyword
`exit()`: is the function
If you convert a Bash script into a function, you typically replace exit N with return N. The code that calls the function will treat the return value the same as it would an exit code from a subprocess.
Using exit inside the function will force the entire script to end.
Adding an actionable aspect to a few of the other answers:
Both can give exit codes - default or defined by the function, and the only 'default' is zero for success for both exit and return. Any status can have a custom number 0-255, including for success.
Return is used often for interactive scripts that run in the current shell, called with . script.sh for example, and just returns you to your calling shell. The return code is then accessible to the calling shell - $? gives you the defined return status.
Exit in this case also closes your shell (including SSH connections, if that's how you're working).
Exit is necessary if the script is executable and called from another script or shell and runs in a subshell. The exit codes then are accessible to the calling shell - return would give an error in this case.
First of all, return is a keyword and exit is a function.
That said, here's a simplest of explanations.
return
It returns a value from a function.
exit
It exits out of or abandons the current shell.

Could the shell function return value not exceed 255? [duplicate]

This question already has answers here:
ExitCodes bigger than 255, possible?
(3 answers)
Return value range of the main function
(7 answers)
Closed 4 years ago.
#!/usr/bin/env bash
# set -x
readonly err_code=256
my_function () {
return $err_code
}
my_function
echo $? # print 0
If the err_code exceed the 255, all the top bits will be dropped just like unsigned byte, how to explain this? Is there any feature document for this? I googled a lot w/o luck.
Thanks!
UPDATE:
Okay, I got it, it doesn't just happen only in shell but Unix-based system, the shell function is also called by command substitution.
Thanks for linked questions!
If you look at man bash and search for EXIT STATUS you will find the following explanation:
EXIT STATUS
The exit status of an executed command is the value returned by the waitpid system call or equivalent
function. Exit statuses fall between 0 and 255, though, as explained below, the shell may use values
above 125 specially. Exit statuses from shell builtins and compound commands are also limited to this
range. Under certain circumstances, the shell will use special values to indicate specific failure modes.
For the shell's purposes, a command which exits with a zero exit status has succeeded. An exit status of
zero indicates success. A non-zero exit status indicates failure. When a command terminates on a fatal
signal N, bash uses the value of 128+N as the exit status.
If a command is not found, the child process created to execute it returns a status of 127. If a command
is found but is not executable, the return status is 126.
If a command fails because of an error during expansion or redirection, the exit status is greater than
zero.
Shell builtin commands return a status of 0 (true) if successful, and non-zero (false) if an error occurs
while they execute. All builtins return an exit status of 2 to indicate incorrect usage, generally
invalid options or missing arguments.
Bash itself returns the exit status of the last command executed, unless a syntax error occurs, in which
case it exits with a non-zero value. See also the exit builtin command below.
If you really want to return values greater than 125, you can use echo instead of return like this:
#!/usr/bin/env bash
my_function () {
echo 256
}
retval=$( my_function )
echo $retval

OK to omit "exit 0" at end of Ruby script?

On Ubuntu 14's Ruby 1.9.3, when I run the script
#!/usr/bin/env ruby
and the script
#!/usr/bin/env ruby
exit 0
they do the same thing. In particular, a subsequent echo $? prints 0. How universal is this behavior? Can I safely omit exit 0 from the end of a nontrivial script?
Universally in UNIX, 0 is reserved for success and codes other than 0 - different sorts of errors.
In any normal language, unless your program throws some sort of exception or explicitly exits with a different code, you can safely assume that it exited with 0.
As per the documentation of Process#exit:
exit(status=true)
[...]The optional parameter is used to return a status code to the invoking environment. true and FALSE of status means success and failure respectively.
The interpretation of other integer values are system dependent.
Meaning Ruby exits with success by default, whatever success means for the underlying system.
As per the documentation of exit codes from The Linux Documentation Project:
[...] A successful command returns a 0, while an unsuccessful one returns a non-zero value that usually can be interpreted as an error code. Well-behaved UNIX commands, programs, and utilities return a 0 exit code upon successful completion, though there are some exceptions. [...]
Meaning you are will get 0 in a UNIX environments.
As per Microsoft's documentation on exit codes:
ERROR_SUCCESS
0 (0x0)
The operation completed successfully.
Meaning you will also get zero in Windows.

What does $? mean immediately after trying to execute an invalid command in the Bourne shell?

I know the $? means the return value of the lastly executed command. I was curious; if the command is invalid, then what will $? be?
It was 127. What does it mean? Why is it 127?
> echo a
a
> echo $?
0
> invalidcommandasdf
invalidcommandasdf: not found
> echo $?
127
The exit status does double duty: it might return information from a program, but it also might return information from whoever ran the program about how the program exited. While a program can, in theory, have any exit code in the range 0 to 255, many of them are assigned special meaning by, say, the POSIX standard, and are not available for use by the program itself.
126 and 127, for instance, are for use by the shell (or other command runner) running the command. 127 means the command could not be found, and 126 means the command was found, but wasn't executable.
Any exit status greater than 128 indicates the program exited due to a signal: 129 when it exits due to signal 1, 130 due to signal 2, etc. In general, 128 + k means it exited due to signal k.
(I'm not sure if 128 itself is reserved for anything in particular.)
In practice, this means your command should not explicitly use any exit code greater than 125. That generally shouldn't be a problem; most commands don't need to distinguish between 125 different errors (0, of course, means it exited without error.) curl is an example of a program that uses a lot of different codes, but even it only uses most of the available values between 1 and 90.
$? gives the exist status code of last executed command/process. 127 status code means Command Not found
for more detail : bash-shell-exit-status/
The primary use of "$?" is to check if the last run command has exit value true or false. You will get output as '0' or '1' where '0' is returned if the last run command is true and '1' if its false.
For unknown commands you will get output such as you have shown.
You can try this by simple using random string (sajdgh / uytwegf) as unrecognized commands and you can see you get a different output.
However the primary use of this command is check the logical status of last used command. Fire ls and see the output of "echo $?" will be '0' now just try 'cat unknown.txt' (considering you actually dont have file named 'unknown.txt') you will get output as '1'

Difference between return and exit in Bash functions

What is the difference between the return and exit statement in Bash functions with respect to exit codes?
From man bash on return [n];
Causes a function to stop executing and return the value specified by n to its caller. If n is omitted, the return status is that of the last command executed in the function body.
... on exit [n]:
Cause the shell to exit with a status of n. If n is omitted, the exit status is that of the last command executed. A trap on EXIT is executed before the shell terminates.
EDIT:
As per your edit of the question, regarding exit codes, return has nothing to do with exit codes. Exit codes are intended for applications/scripts, not functions. So in this regard, the only keyword that sets the exit code of the script (the one that can be caught by the calling program using the $? shell variable) is exit.
EDIT 2:
My last statement referring exit is causing some comments. It was made to differentiate return and exit for the understanding of the OP, and in fact, at any given point of a program/shell script, exit is the only way of ending the script with an exit code to the calling process.
Every command executed in the shell produces a local "exit code": it sets the $? variable to that code, and can be used with if, && and other operators to conditionally execute other commands.
These exit codes (and the value of the $? variable) are reset by each command execution.
Incidentally, the exit code of the last command executed by the script is used as the exit code of the script itself as seen by the calling process.
Finally, functions, when called, act as shell commands with respect to exit codes. The exit code of the function (within the function) is set by using return. So when in a function return 0 is run, the function execution terminates, giving an exit code of 0.
return will cause the current function to go out of scope, while exit will cause the script to end at the point where it is called. Here is a sample program to help explain this:
#!/bin/bash
retfunc()
{
echo "this is retfunc()"
return 1
}
exitfunc()
{
echo "this is exitfunc()"
exit 1
}
retfunc
echo "We are still here"
exitfunc
echo "We will never see this"
Output
$ ./test.sh
this is retfunc()
We are still here
this is exitfunc()
I don't think anyone has really fully answered the question because they don't describe how the two are used. OK, I think we know that exit kills the script, wherever it is called and you can assign a status to it as well such as exit or exit 0 or exit 7 and so forth. This can be used to determine how the script was forced to stop if called by another script, etc. Enough on exit.
return, when called, will return the value specified to indicate the function's behavior, usually a 1 or a 0. For example:
#!/bin/bash
isdirectory() {
if [ -d "$1" ]
then
return 0
else
return 1
fi
echo "you will not see anything after the return like this text"
}
Check like this:
if isdirectory $1; then echo "is directory"; else echo "not a directory"; fi
Or like this:
isdirectory || echo "not a directory"
In this example, the test can be used to indicate if the directory was found. Notice that anything after the return will not be executed in the function. 0 is true, but false is 1 in the shell, different from other programming languages.
For more information on functions: Returning Values from Bash Functions
Note: The isdirectory function is for instructional purposes only. This should not be how you perform such an option in a real script.*
Remember, functions are internal to a script and normally return from whence they were called by using the return statement. Calling an external script is another matter entirely, and scripts usually terminate with an exit statement.
The difference "between the return and exit statement in Bash functions with respect to exit codes" is very small. Both return a status, not values per se. A status of zero indicates success, while any other status (1 to 255) indicates a failure. The return statement will return to the script from where it was called, while the exit statement will end the entire script from wherever it is encountered.
return 0 # Returns to where the function was called. $? contains 0 (success).
return 1 # Returns to where the function was called. $? contains 1 (failure).
exit 0 # Exits the script completely. $? contains 0 (success).
exit 1 # Exits the script completely. $? contains 1 (failure).
If your function simply ends without a return statement, the status of the last command executed is returned as the status code (and will be placed in $?).
Remember, return and exit give back a status code from 0 to 255, available in $?. You cannot stuff anything else into a status code (e.g., return "cat"); it will not work. But, a script can pass back 255 different reasons for failure by using status codes.
You can set variables contained in the calling script, or echo results in the function and use command substitution in the calling script; but the purpose of return and exit are to pass status codes, not values or computation results as one might expect in a programming language like C.
Sometimes, you run a script using . or source.
. a.sh
If you include an exit in the a.sh, it will not just terminate the script, but end your shell session.
If you include a return in the a.sh, it simply stops processing the script.
exit terminates the current process; with or without an exit code, consider this a system more than a program function. Note that when sourcing, exit will end the shell. However, when running, it will just exit the script.
return from a function go back to the instruction after the call, with or without a return code. return is optional and it's implicit at the end of the function. return can only be used inside a function.
I want to add that while being sourced, it's not easy to exit the script from within a function without killing the shell. I think, an example is better on a 'test' script:
#!/bin/bash
function die(){
echo ${1:=Something terrible wrong happen}
#... clean your trash
exit 1
}
[ -f /whatever/ ] || die "whatever is not available"
# Now we can proceed
echo "continue"
doing the following:
user$ ./test
Whatever is not available
user$
test -and- the shell will close.
user$ . ./test
Whatever is not available
Only test will finish and the prompt will show.
The solution is to enclose the potentially procedure in ( and ):
#!/bin/bash
function die(){
echo $(1:=Something terrible wrong happen)
#... Clean your trash
exit 1
}
( # Added
[ -f /whatever/ ] || die "whatever is not available"
# Now we can proceed
echo "continue"
) # Added
Now, in both cases only test will exit.
The OP's question:
What is the difference between the return and exit statement in BASH functions with respect to exit codes?
Firstly, some clarification is required:
A (return|exit) statement is not required to terminate execution of a (function|shell). A (function|shell) will terminate when it reaches the end of its code list, even with no (return|exit) statement.
A (return|exit) statement is not required to pass a value back from a terminated (function|shell). Every process has a built-in variable $? which always has a numeric value. It is a special variable that cannot be set like "?=1", but it is set only in special ways (see below *).
The value of $? after the last command to be executed in the (called function | sub shell) is the value that is passed back to the (function caller | parent shell). That is true whether the last command executed is ("return [n]"| "exit [n]") or plain ("return" or something else which happens to be the last command in the called function's code.
In the above bullet list, choose from "(x|y)" either always the first item or always the second item to get statements about functions and return, or shells and exit, respectively.
What is clear is that they both share common usage of the special variable $? to pass values upwards after they terminate.
* Now for the special ways that $? can be set:
When a called function terminates and returns to its caller then $? in the caller will be equal to the final value of $? in the terminated function.
When a parent shell implicitly or explicitly waits on a single sub shell and is released by termination of that sub shell, then $? in the parent shell will be equal to the final value of $? in the terminated sub shell.
Some built-in functions can modify $? depending upon their result. But some don't.
Built-in functions "return" and "exit", when followed by a numerical argument both set $? with their argument, and terminate execution.
It is worth noting that $? can be assigned a value by calling exit in a sub shell, like this:
# (exit 259)
# echo $?
3
In simple words (mainly for newbie in coding), we can say,
`return`: exits the function,
`exit()`: exits the program (called as process while running)
Also if you observed, this is very basic, but...,
`return`: is the keyword
`exit()`: is the function
If you convert a Bash script into a function, you typically replace exit N with return N. The code that calls the function will treat the return value the same as it would an exit code from a subprocess.
Using exit inside the function will force the entire script to end.
Adding an actionable aspect to a few of the other answers:
Both can give exit codes - default or defined by the function, and the only 'default' is zero for success for both exit and return. Any status can have a custom number 0-255, including for success.
Return is used often for interactive scripts that run in the current shell, called with . script.sh for example, and just returns you to your calling shell. The return code is then accessible to the calling shell - $? gives you the defined return status.
Exit in this case also closes your shell (including SSH connections, if that's how you're working).
Exit is necessary if the script is executable and called from another script or shell and runs in a subshell. The exit codes then are accessible to the calling shell - return would give an error in this case.
First of all, return is a keyword and exit is a function.
That said, here's a simplest of explanations.
return
It returns a value from a function.
exit
It exits out of or abandons the current shell.

Resources