Returning Values from Bash Functions
Summary: Return exit codes or values from functions.
Bash functions are essential for organizing and reusing code within shell scripts. Like functions in other programming languages, Bash functions allow you to compartmentalize tasks and logic. However, returning values from Bash functions can be confusing for those new to shell scripting, since Bash handles "return values" differently compared to languages like Python or JavaScript.
In this article, you'll learn how Bash functions return exit codes and how you can return actual values for further processing.
Exit Codes vs. Output Values
In Bash:
- Exit codes — Used to indicate success (
0
) or failure (non-zero) of a command or function. Accessed via$?
. - Output values — Text data that a function "returns" by printing to
stdout
, which can be captured using command substitution.
These concepts are central to returning information from Bash functions.
Returning Exit Codes from Bash Functions
By default, when a Bash function ends, its exit status is the exit status of the last command executed within the function.
You can explicitly set the exit status using the return
command:
my_function() {
if [[ -f "$1" ]]; then
echo "File exists."
return 0
else
echo "File does not exist."
return 1
fi
}
my_function "/etc/passwd"
echo "Function exited with status: $?"
Key points:
return <number>
sets the function's exit code.- If you don't use
return
, the exit code is that of the last command executed in the function. - Exit codes should be integer values between 0 and 255.
- Use exit codes for success/failure signals, not for returning data.
Returning Values from Bash Functions
While you can’t "return" a data value with the return
statement, you can produce output within the function and capture that output using command substitution.
Example: Capturing Function Output
get_current_user() {
echo "$USER"
}
user_name=$(get_current_user)
echo "The current user is: $user_name"
In this example:
get_current_user
prints the username.$(get_current_user)
captures the output and assigns it touser_name
.
Example: Function to Add Numbers
add_numbers() {
local sum=$(( $1 + $2 ))
echo "$sum"
}
result=$(add_numbers 7 5)
echo "Sum is: $result"
Combining Exit Codes and Output
You can use both exit codes and command output for more complex scripts.
find_file() {
if [[ -f "$1" ]]; then
echo "$1"
return 0
else
return 1
fi
}
if file_path=$(find_file "/tmp/mydata.txt"); then
echo "File found: $file_path"
else
echo "File not found!"
fi
Explanation:
- If the file is found,
find_file
outputs its path and returns0
. - If not, it returns exit code
1
with no output. - The
if
statement checks if the function succeeded and captures output intofile_path
.
Returning Arrays and Multiple Values
Returning complex data like arrays requires a different approach. You can echo values as a string and parse them, or use Bash features to set global variables.
Example: Return Multiple Values
get_date_time() {
echo "$(date '+%Y-%m-%d') $(date '+%H:%M:%S')"
}
read current_date current_time <<< "$(get_date_time)"
echo "Date: $current_date, Time: $current_time"
Example: Setting Global/Output Variable
get_files() {
files=( *.txt )
}
get_files
echo "Text files: ${files[@]}"
In this pattern, the function populates a variable declared outside its scope.
Best Practices
- Use
return
to indicate success/failure — not for returning data. - Print values to stdout from functions if you want to capture their "return value."
- Use local variables inside functions to avoid polluting global scope.
- Document your functions' exit codes and output format for clarity.
Conclusion
While Bash doesn't support returning values from functions in the same way as many programming languages, you can use function output and exit codes effectively for script logic and data transfer. With these techniques, you can write robust, maintainable Bash functions that interact with each other cleanly and predictably.