# If This, Then That: if and \[\[ \]\]

if lets a script choose: the commands after then run only when a test passes, \[\[ \]\] compares text with == and whole numbers with -lt and its friends, and if can also ask whether any command worked.

Apprentice · Unix · Linux · Updated November 10, 2026

## After this lesson you can

- Write an if statement with elif and else, comparing text with == and != inside \[\[ \]\]
- Compare whole numbers in \[\[ \]\] with -eq, -ne, -lt, -le, -gt and -ge, and explain why &lt; compares them as text
- Run commands only when another command worked, by putting that command itself after if

## Key takeaways

- if, then, else and fi let a script choose: the lines after then run only when the test passes, and the lines after else run when it doesn't.
- elif adds another test, tried only when every test before it failed.
- Inside [[ ]], == and != compare text, and -eq, -lt, -gt and their friends compare whole numbers. The spaces inside the brackets are required.
- < inside [[ ]] compares text the way a dictionary does, so [[ 10 < 9 ]] passes. Use -lt for numbers.
- if checks an exit code, where 0 means yes. [[ ]] is a command that answers 0 or 1, and any command, such as cp, can follow if.

Every evening you copy your essay into a backup folder, and a script could do it for you. But a script that runs the same lines every time is like a vending machine that drops a snack whether you paid or not: it copies when you didn't mean it to, and says "Copied" even when the copy failed. Real applications decide: an installer asks "Continue?", and a backup tool checks before it copies. In bash, deciding starts with `if`, and administrators' scripts are full of it: "if the disk is nearly full, send a warning".

These lines make the chapter's practice folder of school work. They're safe to run again:

```bash
mkdir -p ~/terminal-practice/smart-backup && cd ~/terminal-practice/smart-backup
printf 'Why the Town Library Matters\nFirst draft, two pages.\n' > essay.txt
printf 'Chapter 4: read by Friday\nLab report due Monday\n' > notes.txt
printf 'Hatchet\nThe Hobbit\nA Wrinkle in Time\n' > reading-list.txt
touch empty-draft.txt
mkdir -p photos && touch photos/science-fair.jpg
```

## if, elif, else, fi

You already decide this way: if it's raining, take the umbrella; otherwise, your sunglasses. Bash writes it as `if TEST; then … else … fi`, read the way it's written: "if the test passes, then do these, else do those". `fi` is `if` backwards and marks the end. `elif` (read "else if") adds another test, tried only when the ones before it failed; `elif` and `else` are both optional. The usual test, `[[ ]]` (read "test"), checks one thing. Open `nano backup.sh` and write a backup that asks first, with `read` from *Asking Questions: read*:

```bash
#!/usr/bin/env bash
# backup.sh: copies essay.txt into backup/, if you say yes.
read -r -p "Back up essay.txt? (yes/no) " answer
if [[ "$answer" == "yes" ]]; then
  mkdir -p backup
  cp essay.txt backup/
  echo "Copied essay.txt."
elif [[ "$answer" == "no" ]]; then
  echo "Nothing copied."
else
  echo "Please answer yes or no."
fi
```

Save, `chmod +x backup.sh`, and run `./backup.sh` twice, answering `yes`, then `maybe`:

```text
Back up essay.txt? (yes/no) yes
Copied essay.txt.
Back up essay.txt? (yes/no) maybe
Please answer yes or no.
```

Bash tries the tests in order and runs only the first that passes.

## Comparing text: == and !=

`==` (read "is the same as") passes when two pieces of text match exactly, and `!=` (read "is not") when they differ. Every capital counts: answer `Yes`, and the script says "Please answer yes or no." Spaces count too: without the one after `[[`, bash reads `[[maybe` as a command's name:

```bash
answer=maybe
[[$answer == yes]]
```

```text
bash: [[maybe: command not found
```

Keep the double quotes around `"$answer"` as well, the habit from *Quotes: Double, Single and None*.

## Comparing numbers: -lt and its friends

A script should check it was given a file to copy. `$#` is how many arguments were typed (*Arguments: $1, $# and "$@"*), and numbers have their own comparisons:

| Write | Read it | Passes when the left number is |
|---|---|---|
| `-eq` | "equal" | the same as the right one |
| `-ne` | "not equal" | different |
| `-lt` | "less than" | smaller |
| `-le` | "less than or equal" | smaller or the same |
| `-gt` | "greater than" | bigger |
| `-ge` | "greater than or equal" | bigger or the same |

Why not `<`? Inside `[[ ]]`, `<` compares text the way a dictionary sorts words, and 1 comes before 9. At the prompt, a `;` stands in for each line break:

```bash
if [[ 10 < 9 ]]; then echo "less"; else echo "not less"; fi
if [[ 10 -lt 9 ]]; then echo "less"; else echo "not less"; fi
```

```text
less
not less
```

## if on a command: did it work?

Here's the secret of `if`: it runs a command and looks at its exit code (*Did It Work? Exit Codes, && and ||*), where 0 means yes. `[[ ]]` is a command that answers 0 when its test passes and 1 when it doesn't, so any command can follow `if`, `cp` included. Here's `backup.sh` grown up, copying whichever file you name:

```bash
#!/usr/bin/env bash
# backup.sh: copies the file you name into backup/.
if [[ $# -lt 1 ]]; then
  echo "Usage: ./backup.sh FILE"
  exit 1
fi
mkdir -p backup
if cp "$1" backup/; then
  echo "Copied $1."
else
  echo "The copy failed. Nothing was backed up."
  exit 1
fi
```

`exit 1` stops the script and hands back exit code 1, "it didn't work". Run it with no name, a name, then a typo:

```bash
./backup.sh
./backup.sh essay.txt
./backup.sh essay.txs
```

```text
Usage: ./backup.sh FILE
Copied essay.txt.
cp: cannot stat 'essay.txs': No such file or directory
The copy failed. Nothing was backed up.
```

`cp`'s own message differs between systems; your script's line doesn't. Tutorials also write single brackets, `[ "$temp" -gt 90 ]`: the older test command, much the same, but `[[ ]]` forgives more. `if` and `[[ ]]` work in zsh too.

## Check yourself

2 questions to try on the lesson page.

## So what

With `if`, `[[ ]]` and exit codes, a script stops doing the same thing every time and starts doing the right thing: asking first, explaining how to run it, and owning up when something failed.

## Key terms

- [if Statement](https://www.ask-codey.com/glossary/if-statement-unix)
- [Test Command](https://www.ask-codey.com/glossary/test-command)
- [Exit Code](https://www.ask-codey.com/glossary/exit-code)
- [Shell Script](https://www.ask-codey.com/glossary/shell-script)

## Cheat sheets

- [If This, Then That: if and \[\[ \]\]](https://www.ask-codey.com/cheat-sheets/bash-if-statements-cheat-sheet)

## Related

- [Checking Before You Act: File Tests](https://www.ask-codey.com/lessons/bash-file-tests)
- [Menus and Choices: case and select](https://www.ask-codey.com/lessons/bash-case-and-select)
- [Did It Work? Exit Codes, && and ||](https://www.ask-codey.com/lessons/bash-exit-codes)
- [Asking Questions: read](https://www.ask-codey.com/lessons/bash-reading-input)

Source: https://www.ask-codey.com/lessons/bash-if-statements
