summaryrefslogtreecommitdiff
path: root/prompts/skills/bash-best-practices/reference/functions.md
blob: 083b7a26e6b76681e7d4b3079991b33c63930c0c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# Bash Function Patterns

## Function Naming and Namespacing

- Prefer the POSIX-compatible form: `name() { ... }`
- Emulate namespaces with `::`, e.g. `pkg::lang::action`.
- Use `FUNCNAME[0]` for self-aware logging.

```bash
log() {
    local -r callee=${FUNCNAME[1]}
    echo "$callee: $*" >&2
}
```

## Private / Internal Functions

Mark internal helpers with a leading underscore so the public API is obvious: `module::_helper`. This matches the convention used by many Bash projects.

```bash
# Public
foo::generate () { ... }

# Internal only
foo::_sort_entries () { ... }
```

## Function Arguments: Assign-then-Shift

Assign function arguments to named `local` variables immediately using `$1`, then `shift`. This makes adding and removing arguments easy without renumbering.

```bash
some_function () {
    local -r param_foo="$1"; shift
    local -r param_bar="$1"; shift
    local -r param_baz="$1"; shift
}
```

## Scope and Functions

- Functions declared inside other functions are global once defined.
- `export -f function_name` makes a function available in subshells (e.g. `xargs -P`).
- `local` variables have dynamic scope: they are visible down the call stack.

## Chaining Conditionals

Functions return exit statuses and can be chained in conditionals.

```bash
if deploy_check || smoke_test; then
    echo "All good."
else
    echo "Something failed." >&2
fi
```

## `case` for Multi-Branch String Dispatch

Replace long `if/elif` chains with `case ... esac` when matching literal string patterns. It is more readable, avoids quoting pitfalls, and performs exact matching.

```bash
case "$line" in
    '* ')
        html::make_list_item "$line"
        ;;
    '# '*)
        html::make_heading "$line" 1
        ;;
    '## '*)
        html::make_heading "$line" 2
        ;;
    *)
        html::make_paragraph "$line"
        ;;
esac
```