Shell Script Functions: Definition, Usage, and Advanced Patterns

Shell Functions

Defining Functions

Functions in shell scripts encapsulate reusable blocks of code. There are two common syntax styles:

# Style 1: Using the function keyword
function my_function {
    commands
}

# Style 2: Bash-compatible parentheses syntax
my_function() {
    commands
}

Inspecting Defined Functions

The declare builtin provides introspection capabilities for functions:

# List all function names
declare -F

# Display full function definitions
declare -f

# Show definition of a specific function
declare -f function_name

# List a specific function name
declare -F function_name

Return Values

Shell functions exit with status codes rather than traditional return values. The return statement sets the exit status (0-255), which becomes available via the $? special variable:

calculate() {
    local input
    read -p "Enter a number: " input
    result=$((input * 3))
    return $result
}

calculate
current_status=$?

Important considerations:

  • $? captures only the most recent command's exit status
  • Status codes wrap around: values beyond 255 are reduced via modulo 256

Parameter Passing

Functions access positional parameters just like the main script:

add_values() {
    local total=$(($1 + $2))
    echo "Sum: $total"
}

read -p "First number: " x
read -p "Second number: " y
add_values $x $y

# Alternative: pass script arguments directly
add_values $1 $2

Variable Scope

By default, shell variables have global scope throughout the script. The local keyword restricts variable visibility to the function body:

#!/bin/bash

process_data() {
    echo "Global var before: $global_var"
    
    local local_var=50
    echo "Local var inside function: $local_var"
    
    global_var=200
}

####### script start #######
global_var=100
echo "Global var before call: $global_var"
process_data
echo "Global var after call: $global_var"

Output demonstrates that global_var persists outside the function while local_var remains inaccessible:

Global var before call: 100
Global var before: 100
Local var inside function: 50
Global var after call: 200

Function Invocation Methods

Functions can be defined and used in multiple contexts:

  • Interactive shell: Define directly at the command prompt
  • Embedded in scripts: Include function definitions before the main execution block
  • External library files: Store functions in separate files and source them when needed

Practical Example: IP Adress Conversion

This script converts dotted decimal IP addresses to binary representation:

#!/bin/bash

decimal_to_binary() {
    local decimal=$1
    local binary=""
    local digit
    
    for ((i=0; i<8; i++)); do
        digit=$((decimal % 2))
        binary="${digit}${binary}"
        decimal=$((decimal / 2))
    done
    echo "$binary"
}

convert_ip() {
    local ip_addr=$1
    local octet
    local result=""
    
    for ((i=0; i<4; i++)); do
        octet=${ip_addr%%.*}
        ip_addr=${ip_addr#*.}
        result+=$(decimal_to_binary $octet)
        if [ $i -lt 3 ]; then
            result+="."
        fi
    done
    echo "$result"
}

######## main ########
read -p "Enter IP address (dotted decimal): " user_ip
binary_ip=$(convert_ip "$user_ip")
echo "Binary representation: $binary_ip"

Practical Example: Pattern Display

Generate a diamond pattern with configurable dimensions:

#!/bin/bash

print_upper() {
    local rows=$1
    local row space stars
    
    for ((row=1; row<=rows; row++)); do
        space=$((rows - row))
        stars=$((2 * row - 1))
        
        printf "%${space}s" ""
        printf '%*s\n' "$stars" "" | tr ' ' '*'
    done
}

print_lower() {
    local rows=$1
    local row space stars
    
    for ((row=rows-1; row>=1; row--)); do
        space=$((rows - row))
        stars=$((2 * row - 1))
        
        printf "%${space}s" ""
        printf '%*s\n' "$stars" "" | tr ' ' '*'
    done
}

######## main ########
read -p "Enter diamond size: " size
print_upper $size
print_lower $size

Recursive Functions

A function can call itself, enabling elegant solusions for problems with recursive structure.

Factorial Calculation

#!/bin/bash

factorial() {
    local n=$1
    
    if [ $n -le 1 ]; then
        echo 1
    else
        local previous=$(factorial $((n - 1)))
        echo $((n * previous))
    fi
}

######## main ########
read -p "Enter a positive integer: " number
result=$(factorial $number)
echo "Factorial of $number is: $result"

Directory Traversal

Recursive functions excel at traversing directory trees:

#!/bin/bash

extract_paths() {
    local directory=$1
    local indent=$2
    local entry
    
    for entry in "$directory"/*; do
        if [ -d "$entry" ]; then
            echo "${indent}[DIR] ${entry##*/}"
            extract_paths "$entry" "$indent  "
        elif [ ! -x "$entry" ]; then
            echo "${indent}[FILE] ${entry##*/}"
        fi
    done
}

######## main ########
IFS=':' read -ra paths <<< "$PATH"
for p in "${paths[@]}"; do
    echo "Directory: $p"
    if [ -d "$p" ]; then
        extract_paths "$p" "  "
    fi
done

Function Library Files

Reusable function collections can be stored in separate files and imported via source or ..

Creating a Library

Save this as mathlib.sh:

add() {
    echo $(($1 + $2))
}

subtract() {
    echo $(($1 - $2))
}

multiply() {
    echo $(($1 * $2))
}

divide() {
    if [ $2 -eq 0 ]; then
        echo "Error: division by zero"
        return 1
    fi
    echo $(($1 / $2))
}

factorial() {
    local n=$1
    if [ $n -le 1 ]; then
        echo 1
    else
        echo $((n * $(factorial $((n - 1)))))
    fi
}

Using the Library

#!/bin/bash

source mathlib.sh

read -p "Enter first number: " num1
read -p "Enter second number: " num2

sum=$(add $num1 $num2)
diff=$(subtract $num1 $num2)
prod=$(multiply $num1 $num2)
quot=$(divide $num1 $num2)
fact=$(factorial $num1)

echo "Sum:      $sum"
echo "Difference: $diff"
echo "Product:   $prod"
echo "Quotient:  $quot"
echo "Factorial: $fact"

Function libraries provide modularity and code reuse across multiple scripts, reducing duplication and maintenance overhead.

Tags: Shell Scripting bash functions automation Linux

Posted on Wed, 03 Jun 2026 16:55:32 +0000 by cesy