Przejdลบ do treล›ci

๐Ÿง  Functions & Script Libraries

Functions and script libraries allow shell code to be organized into reusable, maintainable units. They are essential for building scalable automation, reducing duplication, and enforcing consistent behavior across scripts.


๐ŸŽ“ Who This Is For

  • Engineers building shared tooling or automation frameworks
  • DevOps/SRE teams standardizing shell code across environments
  • Developers maintaining large or multiโ€‘file shell projects
  • Anyone writing scripts that must be testable, modular, and predictable

๐Ÿงฉ Role in the Ecosystem

Functions and libraries provide:

  • Encapsulation of logic
  • Reuse across multiple scripts
  • Clear separation of responsibilities
  • Improved readability and maintainability
  • A foundation for building higherโ€‘level tooling

They are the closest equivalent to modules in POSIX shell scripting.


๐Ÿงฉ Key Concepts

1. Function Definitions

1
2
3
log() {
  printf '[%s] %s\n' "$(date -Is)" "$*" >&2
}
  • Functions must be defined before use in POSIX sh
  • They inherit the parent shell environment
  • They cannot return values directly (use stdout or exit codes)

2. Return Codes

1
2
3
do_step() {
  command || return 1
}

Functions communicate success/failure via exit codes.

3. Script Libraries

1
2
3
4
5
6
# lib/log.sh
log() { ... }

# main.sh
. "$(dirname "$0")/lib/log.sh"
log "Starting..."
  • Loaded using . (POSIX) or source (bash)
  • Executed in the current shell, not a subshell
  • Can define functions, variables, and configuration

4. Namespacing

Use prefixes to avoid collisions:

1
2
fs_read() { ... }
fs_write() { ... }

๐Ÿ”ง Notable Techniques

Argument Handling

1
2
3
4
greet() {
  name="$1"
  echo "Hello, $name"
}

Returning Values via stdout

1
2
3
4
5
get_timestamp() {
  date -Is
}

ts="$(get_timestamp)"

Returning Values via Variables (bash/ksh)

1
2
3
4
5
get_pid() {
  pid=$$
}
get_pid
echo "$pid"

Library Discovery

1
2
SCRIPT_DIR="$(CDPATH= cd -- "$(dirname "$0")" && pwd)"
. "$SCRIPT_DIR/lib/utils.sh"

Guarding Against Multiple Loads

1
2
[ -n "${_UTILS_LOADED:-}" ] && return
_UTILS_LOADED=1

โš ๏ธ Limitations & Pitfalls

  • No true namespaces โ€” name collisions are common
  • No private functions or variables
  • Libraries execute in the current shell (side effects persist)
  • Functions cannot return structured data
  • Subshells discard variable changes
  • Bashโ€‘only features break portability

๐Ÿง  When to Use Functions & Libraries

  • When logic is reused across multiple scripts
  • When scripts grow beyond a few dozen lines
  • When building internal tooling or automation frameworks
  • When enforcing consistent logging, error handling, or formatting
  • When improving readability and maintainability

โŒ When Not to Use Them

  • Extremely small oneโ€‘off scripts
  • Scripts intended to run in highly restricted environments
  • When portability across shells is uncertain
  • When the logic is complex enough to justify a real language (Python, Go, etc.)

โœ… Best Practices

  • Keep libraries POSIXโ€‘compliant unless bash is explicitly required
  • Use prefixes for namespacing (log_, fs_, str_)
  • Avoid global state unless necessary
  • Document all public functions at the top of the library
  • Keep functions small and focused
  • Use explicit return codes:
1
return 1
  • Use Parameter Expansion instead of external tools
  • Avoid subshells when persistence is required
  • Load libraries using absolute paths for reliability

๐Ÿงช Testing Functions & Libraries

1
2
3
set -x
. ./lib/log.sh
log "test message"

Test portability:

1
2
3
dash script.sh
bash --posix script.sh
ksh script.sh

Test return codes:

1
2
3
4
5
if myfunc; then
  echo ok
else
  echo fail
fi

๐Ÿง  Summary

Functions and script libraries are the foundation of maintainable shell code. They enable reuse, structure, and clarity โ€” essential for productionโ€‘grade automation. Use them to organize logic, enforce consistency, and build scalable tooling across your shell ecosystem.