Functions
Functions allow you to organize your code like building blocks, making it easier to understand, maintain, and debug. Just as you might break down a complex math problem into smaller steps, functions let you divide your script into logical, focused pieces that each perform a specific task. This not only saves you from writing the same code multiple times but also makes your scripts cleaner and more professional.
When naming functions, follow the same rules as naming variables: use lowercase letters, numbers, and underscores. Avoid using uppercase letters or special characters unless absolutely necessary. Don't start with a number and don't have a space in the function name.
Common Function Syntax Options
| Syntax Style | What It Does | When to Use It |
|---|---|---|
function_name() { commands; } |
Standard POSIX-compliant function definition | For maximum portability across different shells |
function function_name { commands; } |
Bash-specific function definition with keyword. The keyword is the word "function" and it is before the function name. | When working exclusively in Bash environments |
function_name { commands; } |
Simplified Bash function definition | Less common; not recommended for clarity reasons |
Practical Example
When writing functions in bash you needt write the function first before you can call it. You do this by writing the function name followed by parentheses and then the commands to be executed. You then call the function by writing the function name followed by parentheses.
In this example, we are defining three functions: test1, add, and comm. We are then calling each function and echoing the result.
# Standard function definition (recommended)
test1(){
echo "Hello Class"
echo "more here"
}
# Call the function
test1 # Outputs: Hello Class
# Function that performs a calculation
add(){
echo "The numbers added together are $((5 + 3 + 7))"
}
add # Outputs: The numbers added together are 15
# Function that uses external commands
comm(){
echo "The contents of the foo file is $(cat foo.txt)"
}
comm # Outputs: The contents of the foo file is this is the foo.txt file text
Passing Arguments to Functions
When passing arguments to a function, you need to pass them in the order they are defined in the function. You can pass them in the order you want to, but you need to pass them in the order they are defined in the function.
How Arguments Work in Functions
| Parameter | What It Represents | When to Use It |
|---|---|---|
$1 |
First argument passed to the function | To access the first value provided when calling the function |
$2, $3, ... |
Second, third, etc. arguments | When your function accepts multiple inputs |
Practical Examples
In this example, we are defining two functions: add and concat. We are passing three numbers to the add function and two strings to the concat function as arguments.
# Function that takes multiple arguments and performs addition
add(){
echo "we are adding the numbers $1, $2 and $3 the sum is "$(($1+$2+$3))
}
# Call with three numbers
add 10 25 45 # Outputs: we are adding the numbers 10, 25 and 45 the sum is 80
# Function that concatenates two words
concat(){
echo "this is a contactenation of two words $1 $2"
}
# Call with two string arguments
concat "Hello" "World" # Outputs: this is a contactenation of two words Hello World
Returning Values from Functions
When returning values from a function, you need to use the return statement. The return statement will return the value to the calling function. The return statement will also exit the function (meaning the function will stop executing and return the value to the calling function). The return statement can only return integers between 0 and 255. If you return a value greater than 255, it will be truncated to 255. You can also write a return statement without a value, this will return 0. You can capture the return value of a function in a variable by using the $? special variable.
Return Methods in Bash Functions
| Method | What It Does | When to Use It |
|---|---|---|
return [0-255] |
Returns an exit status code | For indicating success (0) or failure (non-zero) |
Practical Examples
Return statement stops execution
In this example, we are demonstrating that the return statement stops execution of the function. The function ret1 echoes "ret1 got called", then returns, and the echo statement after the return will not execute because the function has already exited.
#!/bin/bash
ret1(){
echo "ret1 got called"
return
echo "this is ret1 after a return statement" # This will not run because it is after the return statement
}
ret1 # Outputs: ret1 got called
Returning an integer value
In this example, we are demonstrating how to return an integer value from a function. The function ret2 returns the value 5. We capture this return value using the $? special variable, which contains the exit status of the last command executed. After calling ret2, we store the return value in varRet2 and then echo it to display the value.
#!/bin/bash
ret2(){
echo "this is ret2, returns can only return integers between 0 and 255"
return 5
}
ret2
varRet2=$? # Captures the return value (5) into a variable using the $? special variable
echo $varRet2 # Outputs: 5
Returning a different integer value
In this example, we are demonstrating another function that returns a different integer value. The function ret3 returns the value 3. We capture this return value using $? and store it in varRet3, then echo it to display the value.
#!/bin/bash
ret3(){
echo "this is ret3 returning the integer of 3"
return 3
}
ret3
varRet3=$? # Captures the return value (3)
echo $varRet3 # Outputs: 3
Return value wrapping
In this example, we are demonstrating how return values greater than 255 get wrapped around using modulus 256. The function ret4 attempts to return 500, but since return values can only be between 0 and 255, it gets wrapped to 500 % 256 = 244. We capture this wrapped value using $? and display it. Note that when we echo $? again after the first echo, it shows 0 because $? now contains the exit status of the echo command, not the function's return value.
#!/bin/bash
ret4(){
echo "this is ret4 it returns 244 because it gets wrapped around modulus 256"
echo "500 % 256 = 244"
return 500
}
ret4
varRet4=$? # Captures the return value (244, because 500 wraps to 500 % 256)
echo $varRet4 # Outputs: 244
echo $? # Outputs: 0 (because echo was the last command)
Variable Scope in Functions
Variable scope in functions is the scope of a variable within a function. The scope of a variable is the range of the script that the variable is visible to. The scope of a variable can be local to the function, global to the script, or local to the script. The scope of a variable is determined by the keyword used to declare the variable. The keyword used to declare a variable can be local, global, or local to the script. The keyword used to declare a variable can be local to the function by using the local keyword. The keyword used to declare a variable can be global to the script by using the global keyword. The keyword used to declare a variable can be local to the script by using the local keyword.
| Scope Type | What It Does | When to Use It |
|---|---|---|
local variable_name |
Creates a variable only visible within the function by using the local keyword | To prevent the function from affecting variables in the main script |
| Global variables (default) | Variables accessible throughout the entire script | When the variable needs to be accessed by multiple functions |
Practical Example
In this example, we are demonstrating the scope of a variable in a function. The variable name is declared outside the function and is global to the script. The function changeName modifies the global variable name to "sam". If we uncomment the local name="sam" line and comment out the name="sam" line, the global variable "name" will not be changed. The function echo $name will echo the global variable name which is "sam".
Let's take a look at an example of each first example the "name" variable is global to the script and the function changeName modifies the global variable name to "sam". The second example the "name" variable is local to the function and the function changeName modifies the local variable name to "sam".
# Global variable defined outside function
name="scott"
# Function that modifies the global variable
changeName(){
name="sam"
echo $name
}
changeName # Outputs: sam
echo $name # Outputs: sam (the global variable was changed)
In this example, we are demonstrating the scope of a variable in a function. The variable "name" is declared outside the function and is global to the script. The function changeName modifies the local variable "name" to "sam". The function echo $name will echo the local variable "name" which is "sam". However, the global variable "name" will not be changed because the local variable "name" is not global to the script.
# Local variable defined inside function
name="scott"
changeName(){
local name="sam"
echo $name
}
changeName # Outputs: sam
echo $name # Outputs: scott (the global variable was not changed)
Learning Aids
Tips for Success
- Use meaningful function names - Names should clearly indicate what the function does
- Keep functions focused - Each function should do one thing well
- Document your functions - Add comments explaining the purpose, parameters, and return values
- Validate input parameters - Check that required arguments are provided and valid
- Use local variables by default - Minimize the use of global variables to avoid side effects
- Group related functions together - Organize functions logically in your script
- Test functions individually - Ensure each function works correctly on its own
- Avoid deeply nested functions - Keep the function call hierarchy relatively flat
Common Mistakes to Avoid
- Forgetting to make variables local - Unintentionally modifying global variables can cause bugs
- Relying on undeclared variables - Always initialize variables before using them
- Using incorrect return values - Remember that
returnonly works with values 0-255. If you use a value greater than 255, it will be truncated using modulus 256 to fit within the valid range - Forgetting that functions have their own argument list -
$1inside a function is not the same as$1in the main script - Creating functions with the same name as commands - This can lead to unexpected behavior
- Defining multiple functions with the same name - The second function will override the first one; only the most recent definition will be used when called
- Not checking the number of arguments - Missing arguments can cause your function to fail
- Writing overly complex functions - If a function is too complex, break it into smaller functions
- Using echo for both output and return values - This can make it difficult to capture return values
Best Practices
- Place all functions at the beginning of your script - Define functions before you use them
- Use the POSIX-compliant syntax -
function_name() { commands; }for better portability - Return meaningful exit codes - Use 0 for success and different non-zero values for specific errors
- Include usage examples in comments - Show how the function should be called
- Use clear parameter naming in comments - Document what each parameter represents
- Create a standard error handling approach - Be consistent in how functions report errors
- Modularize complex scripts into separate files - Use
sourceto include function libraries - Write functions that do one thing well - Follow the Unix philosophy of simplicity