# Local Variables and Getting a Value Back

local keeps a function's variables to itself, so it can't change the script's by accident; a function hands back a result by printing it with echo, which the caller catches with $( ), and answers yes or no with return, which if can test.

Journeyman · Unix · Linux · Updated November 10, 2026

## After this lesson you can

- Keep a function's variables to itself with local
- Get a result from a function with echo and $( ), and a yes or no with return

## Key takeaways

- A script's variables are shared with every function in it. local makes a variable the function's own, so it can't change the script's.
- Make every variable inside a function local, the loop's variable too.
- A function hands back a result by printing it, and total=$(sum_minutes 4 3 5) catches it, the same as $(date +%F).
- Everything a function prints is caught, so a function that answers with echo prints nothing else.
- return sets the function's exit code: 0 for yes, 1 for no, ready for if. It can't hand back a number such as 300.

The drive to the coast takes 45 minutes, and you want to know whether the mix fills it. You add a function that adds up half the mix, run the script, and it says the drive is 13 minutes long. Nothing you typed says 13. Picture an office whiteboard that everyone shares: you write the drive's length on it, a coworker uses the same corner for a sum, and your number is gone. The function did its sums on the shared whiteboard. This lesson gives a function scratch paper of its own, and two ways to hand an answer back: a result, such as a total, or a plain yes or no. Every function in a real tool does one or the other; in `spend`, one function will work out a month's total and another will answer "is this a real date?".

## A function that changes your variables

Go into the practice folder from *Functions: Naming a Job* (this line makes it, if it isn't there yet):

```bash
mkdir -p ~/terminal-practice/shuffler && cd ~/terminal-practice/shuffler
```

Write `drive.sh`, make it runnable with `chmod +x drive.sh`, and run it:

```bash
#!/usr/bin/env bash
# drive.sh: how long is each half of the mix, and is the drive long enough?
add_up() {
  total=0
  for m in "$@"; do
    total=$((total + m))
  done
  echo "This half: $total minutes"
}

total=45
add_up 4 3 5
add_up 4 6 3
echo "The drive: $total minutes"
```

```text
This half: 12 minutes
This half: 13 minutes
The drive: 13 minutes
```

The script set `total=45`, the drive's length, and then `add_up` used a variable with the same name for its sum. In a script, every variable is **global**: shared by the whole script, functions included. The function wrote over the drive's length, and nothing warned you.

## local: the function's own scratch paper

Change the first line inside `add_up` to this, and run `./drive.sh` again:

```bash
  local total=0 m
```

```text
This half: 12 minutes
This half: 13 minutes
The drive: 45 minutes
```

`local` makes `total` and `m` this function's own **local variables**. They exist while it runs and disappear when it ends, and the script's `total` is left alone. Make every variable inside a function local, the loop's variable (`m`) too. `local` works only inside a function: at the prompt, or in the main part of a script, bash stops with `local: can only be used in a function`.

## Handing back a result: echo and $( )

`add_up` prints a sentence, which is fine for reading but no use for adding. A function's answer is what it prints, so make it print only the number, and catch it with `$( )`, the way `today=$(date +%F)` catches the date (*Values from Commands: $( ) and $(( ))*). To bash, your function is one more command:

```bash
#!/usr/bin/env bash
# drive.sh: how long is the mix?
sum_minutes() {
  local total=0 m
  for m in "$@"; do
    total=$((total + m))
  done
  echo "$total"
}

first=$(sum_minutes 4 3 5)
second=$(sum_minutes 4 6 3)
echo "The mix: $((first + second)) minutes"
```

```text
The mix: 25 minutes
```

`$( )` catches everything the function prints. Add a friendly `echo "Adding up $# songs..."` inside `sum_minutes`, and `first` holds that sentence as well as the number, so the sum on the last line stops with an arithmetic error. A function that answers with `echo` prints its answer and nothing else.

## return: a yes or no

Some questions have no number for an answer: does the mix fit the drive? Make the drive's length the script's first argument, and add a function that answers yes or no:

```bash
#!/usr/bin/env bash
# drive.sh: does the mix fit the drive?
# Usage: ./drive.sh MINUTES
sum_minutes() {
  local total=0 m
  for m in "$@"; do
    total=$((total + m))
  done
  echo "$total"
}

fits() {
  local minutes=$1 limit=$2
  if [[ $minutes -gt $limit ]]; then
    return 1
  fi
  return 0
}

mix=$(sum_minutes 4 3 5 4 6 3)
if fits "$mix" "$1"; then
  echo "The $mix-minute mix fits the $1-minute drive."
else
  echo "The $mix-minute mix is too long for the $1-minute drive."
fi
```

```bash
./drive.sh 45
./drive.sh 20
```

```text
The 25-minute mix fits the 45-minute drive.
The 25-minute mix is too long for the 20-minute drive.
```

`return` ends the function and sets its **exit code** (*Did It Work? Exit Codes, && and ||*): 0 means yes, it worked, and 1 to 255 mean no. `if` tests that code, the same as it tests `cp` or `[[ ]]` (*If This, Then That: if and [[ ]]*). Without a `return`, a function's exit code is its last command's, so `fits` could be the one line `[[ $minutes -le $limit ]]`.

What `return` can't do is hand back a result. Exit codes only go from 0 to 255:

```bash
add() {
  return $(($1 + $2))
}
add 4 3
echo "$?"
add 200 100
echo "$?"
```

```text
7
44
```

300 wrapped around to 44, with no warning. Use `echo` and `$( )` for results, and `return` for yes or no.

## Check yourself

2 questions to try on the lesson page.

## So what

`local` keeps each function's work to itself, `echo` with `$( )` hands back a result, and `return` answers yes or no, which together let functions be pieces you can trust without reading their insides every time.

## Key terms

- [Local Variable](https://www.ask-codey.com/glossary/local-variable-unix)
- [Global Variable](https://www.ask-codey.com/glossary/global-variable-unix)
- [Command Substitution](https://www.ask-codey.com/glossary/command-substitution)
- [return](https://www.ask-codey.com/glossary/return-unix)
- [Exit Code](https://www.ask-codey.com/glossary/exit-code)

## Cheat sheets

- [Local Variables and Getting a Value Back](https://www.ask-codey.com/cheat-sheets/bash-function-return-values-cheat-sheet)

## Related

- [Functions: Naming a Job](https://www.ask-codey.com/lessons/bash-functions)
- [Values from Commands: $( ) and $(( ))](https://www.ask-codey.com/lessons/bash-command-substitution)
- [Did It Work? Exit Codes, && and ||](https://www.ask-codey.com/lessons/bash-exit-codes)
- [If This, Then That: if and \[\[ \]\]](https://www.ask-codey.com/lessons/bash-if-statements)

Source: https://www.ask-codey.com/lessons/bash-function-return-values
