Bash function: define, call, arguments, `local`, and `return`

Functions in bash let you name a block of commands and call it like a mini-program. You might land here from searches like bash function, bash define function, or bash script function—all of the same pieces: how you declare the body, how arguments map to $1, $2, "$@", how variable scope works, and how return differs from printing a value. For a broader Bash path, the Shell Scripting & Bash course hub links this topic with loops and the rest of the series.

Tested all the commands and code from this article on Ubuntu 25.04, kernel 6.14.0-37-generic, Bash 5.2.37.


Bash define function (two valid shapes)

The portable POSIX-style form:

bash
say() {
  echo "hello"
}

The function keyword (also Bash; slightly more verbose):

bash
function say2 {
  echo "hello again"
}

Call either one by name:

bash
say
say2

Output:

output
hello
hello again

Pick one style per project and stay consistent; both are widely used in real scripts.


Bash function example: parameters ($1, $2, $@)

Inside a function, $1$9 (and beyond with ${10}) are the arguments passed at call time—not the script’s original argv unless you forward them yourself.

bash
show() {
  echo "first=$1 second=$2"
  echo "all together: $*"
}

show "one word" "two"

Output:

output
first=one word second=two
all together: one word two
  • "$@" — each argument as its own word (best default when re-passing).
  • "$*" — one string joined by the first character of IFS (handy sometimes, easy to misuse).

To turn arguments into an array inside the function, use args=("$@") and read split string into array when you are building lists from text.


local vs global (the important detail)

A plain assignment inside a function updates a global shell variable unless you use local (or declare a local in a subshell context). That surprises people who expect “function scope” by default.

bash
f_global() { x=2; }
x=1
f_global
echo "x after f_global (no local): $x"

Output:

output
x after f_global (no local): 2

With local, the outer x stays put:

bash
f_local() {
  local x=3
  echo "inside: $x"
}
x=1
f_local
echo "x after f_local: $x"

Output:

output
inside: 3
x after f_local: 1

Rule of thumb: every temporary variable inside a library-style function should be local unless you deliberately mean to set a global.


Returning status vs returning data

return n sets the function’s exit status for the caller ($? right after the call). Status codes are limited to 0–255; use them for success/failure, not large numbers or strings.

bash
check() { return 2; }
check
echo "return exit: $?"

Output:

output
return exit: 2

To hand a string or number “back” to the caller, print and capture with command substitution, or refactor to write a result variable the caller names.

bash
answer() { echo "result"; }
out=$(answer)
echo "captured: $out"

Output:

output
captured: result

That pattern is how most bash function example snippets pass data without abusing return.


Grouping: { …; } vs ( … )

A brace group runs in the current shell; parentheses run in a subshell, so assignments there do not touch the parent’s variables. Functions already run as a unit; subshells show up more when you wrap pipelines—see while loops for related control-flow patterns.


Small habits that keep functions maintainable

  • Put a one-line comment above non-obvious functions: purpose, parameters, side effects.
  • Quote "$1" when passing paths or user text.
  • Prefer return for status; use echo/printf + $() for data.
  • Avoid return outside a function—it is not exit.

Summary

Define functions with name() { … } or function name { … }, call them like commands, and use $1 / "$@" for arguments. Mark temporaries with local so you do not overwrite globals by accident. Use return only for small integer statuses; print and capture when the caller needs real data back. That covers most bash function patterns you will use in production scripts.

Further reading:

Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)