Sagar.BlogArticle
All posts
All posts
Bash

Functions in Bash — Reusable Blocks of Code

Functions let you name and reuse blocks of commands. Learn how to define, call, and organise Bash functions to make your scripts modular and maintainable.

January 16, 20266 min read
BashFunctionsScripting

Functions are the building blocks of well-organised scripts. Instead of copying and pasting the same commands in multiple places, you define a function once and call it by name. This makes scripts shorter, easier to test, and easier to maintain.

Defining Functions

There are two syntax styles — both are equivalent:

# Style 1 — function keyword (more readable, preferred)
function greet {
    echo "Hello, World!"
}

# Style 2 — POSIX-compatible (no keyword)
greet() {
    echo "Hello, World!"
}

# Call it — just use the name
greet

Define before you call

Bash reads scripts top-to-bottom. A function must be defined before it's called. Common practice: define all functions near the top, then call them in a main function at the bottom.

Function Arguments

Functions receive arguments the same way scripts do — via $1, $2, $@, etc. These are local to the function (they shadow but don't overwrite the script-level positional params).

function greet_user {
    local name="$1"
    local role="${2:-user}"    # default if not provided
    echo "Hello, $name! You are a $role."
}

greet_user "Alice" "admin"    # Hello, Alice! You are a admin.
greet_user "Bob"              # Hello, Bob! You are a user.

Returning Values — The Echo Pattern

return in Bash can only return an integer (0–255) as an exit code, not a string. To "return" a string from a function, print it with echo and capture it with $():

function get_greeting {
    local name="$1"
    echo "Hello, $name!"     # "return" via stdout
}

# Capture the output
message=$(get_greeting "Alice")
echo "$message"     # Hello, Alice!

# You can also use return for status codes
function is_root {
    [[ $EUID -eq 0 ]]    # return 0 (true) if root, 1 if not
}

if is_root; then
    echo "Running as root"
fi

A Practical Example — Logging

#!/usr/bin/env bash

LOG_FILE="/tmp/myscript.log"

function log_info {
    echo "[INFO]  $(date '+%F %T')$*" | tee -a "$LOG_FILE"
}

function log_error {
    echo "[ERROR] $(date '+%F %T')$*" | tee -a "$LOG_FILE" >&2
}

function log_warn {
    echo "[WARN]  $(date '+%F %T')$*" | tee -a "$LOG_FILE"
}

# Usage
log_info "Script started"
log_warn "Disk usage is high"
log_error "Failed to connect to database"

Functions as a Main Structure

#!/usr/bin/env bash

function usage {
    echo "Usage: $0 [options]" >&2
    exit 1
}

function setup {
    log_info "Setting up..."
    mkdir -p /tmp/myapp
}

function cleanup {
    log_info "Cleaning up..."
    rm -rf /tmp/myapp
}

function main {
    [[ $# -eq 0 ]] && usage
    setup
    # ... do work ...
    cleanup
    echo "Done"
}

# Call main with all script arguments
main "$@"
Quick Check

How do you return a string value from a Bash function?

Exercise

Write a function to_upper that:

  1. Takes a string as argument
  2. Returns it in uppercase (use parameter expansion ${var^^})
  3. Call it with "hello world" and store the result in a variable, then print it