if / elif / else
| Since: | POSIX(sh互換) |
|---|
The if statement in Shell Script branches execution based on whether a condition is true (exit status 0) or false (non-zero). Conditions are evaluated using the test command (equivalent to [) or the bash-extended [[ compound command. It handles string comparison, numeric comparison, and file existence checks, and forms the core of script control flow.
Basic Syntax
An if statement is closed with fi. Use elif to chain additional conditions, and else to run a block when none of the conditions match.
| Keyword | Meaning | Description |
|---|---|---|
if | Start of conditional branch | Runs the then block when the following command exits with status 0. |
then | Start of the true branch | Begins the block to execute when the if or elif condition is true. |
elif | Additional condition (else if) | Specifies an additional condition to evaluate when the previous condition was false. Multiple elif clauses can be chained. |
else | Fallback branch | Begins the block to execute when all conditions are false. |
fi | End of conditional branch | Closes the if block (the word "if" spelled backwards). |
# Basic structure of an if statement
if command; then
# Runs when the command exits with status 0 (true)
action_a
elif another_command; then
# Runs when the first condition is false and this one exits with 0 (true)
action_b
else
# Runs when all conditions are false
action_c
fi
The test Command and [ ]
[ is an alias for the test command. When you write [ condition ], it returns exit status 0 (true) if the condition holds, or 1 (false) if it does not. Because ] marks the end of the arguments, a space before the closing bracket is required.
| Syntax | Description |
|---|---|
test condition | Evaluates the condition. POSIX-compliant and works in sh. |
[ condition ] | Exactly equivalent to test. Spaces inside the brackets are required. |
[[ condition ]] | A compound command that extends bash/zsh. Supports && / ||, glob pattern matching, and regular expressions (=~). Not available in sh. |
String Comparison
Use = (or ==) and != for string comparisons. Always wrap variables in double quotes — without them, an empty variable causes an error.
| Operator | True when | Description |
|---|---|---|
[ "$a" = "$b" ] | Exact match | True when strings a and b are equal. POSIX-compliant, works in sh. |
[ "$a" == "$b" ] | Exact match (bash) | Equivalent to =. Inside [[ ]], treated as a glob pattern match. |
[ "$a" != "$b" ] | Not equal | True when strings a and b differ. |
[ -z "$a" ] | Empty string | True when string a has a length of 0 (is empty). |
[ -n "$a" ] | Non-empty string | True when string a has a length of 1 or more. |
[[ "$a" =~ regex ]] | Regex match | Available only in bash [[. The match result is stored in BASH_REMATCH. |
Numeric Comparison
Use dedicated flags for numeric comparisons. Note that < and > perform lexicographic (string) comparison, so do not use them for numbers.
| Operator | Meaning | Description |
|---|---|---|
[ "$a" -eq "$b" ] | Equal | True when numbers a and b are equal. |
[ "$a" -ne "$b" ] | Not equal | True when numbers a and b differ. |
[ "$a" -lt "$b" ] | Less than | True when number a is less than b. |
[ "$a" -le "$b" ] | Less than or equal | True when number a is less than or equal to b. |
[ "$a" -gt "$b" ] | Greater than | True when number a is greater than b. |
[ "$a" -ge "$b" ] | Greater than or equal | True when number a is greater than or equal to b. |
File Tests
Use flags such as -f, -d, and -e to check the state of files and directories. These are commonly used to verify file existence or check permissions before running a script.
| Operator | True when | Description |
|---|---|---|
[ -e "$path" ] | Exists | True when the path exists — whether it is a file, directory, symbolic link, etc. |
[ -f "$path" ] | Regular file | True when the path is a regular file (not a directory or device file). |
[ -d "$path" ] | Directory | True when the path is a directory. |
[ -r "$path" ] | Readable | True when you have read permission on the path. |
[ -w "$path" ] | Writable | True when you have write permission on the path. |
[ -x "$path" ] | Executable | True when you have execute permission on the path. |
[ -s "$path" ] | Size greater than 0 | True when the file exists and is not empty. |
[ -L "$path" ] | Symbolic link | True when the path is a symbolic link. |
Logical Operators
To combine multiple conditions, use && / || inside [[ ]], or -a / -o inside [ ]. Using && / || within [[ ]] is more readable and generally preferred.
| Syntax | Meaning | Description |
|---|---|---|
[[ condA && condB ]] | AND | True when both A and B are true. Requires [[ ]]. |
[[ condA || condB ]] | OR | True when either A or B is true. Requires [[ ]]. |
[ condA ] && [ condB ] | AND (POSIX-compliant) | Connects two [ ] tests with &&. Works in sh. |
[ condA -a condB ] | AND (older syntax) | Works inside [ ], but prone to problems when variables are empty. Not recommended. |
! condition | NOT (negation) | Negates the condition. Used as [ ! -f "$path" ] inside [ ]. |
Sample Code
kof_string_compare.sh
#!/bin/bash
# -----------------------------------------------
# Demonstrates string comparison with if
# using KOF (The King of Fighters) characters
# -----------------------------------------------
# -----------------------------------------------
# Set team members into variables
# -----------------------------------------------
# Members of the Kusanagi team in KOF
team_kusanagi=("Kusanagi Kyo" "Nikaido Benimaru" "Daimon Goro")
# Character name to check (set directly into a variable here)
input_name="Kusanagi Kyo"
echo "=== Exact string match ==="
# Use = to check for an exact string match (always quote variables with double quotes)
if [ "$input_name" = "Kusanagi Kyo" ]; then
echo "${input_name} is the leader of the Kusanagi team."
elif [ "$input_name" = "Nikaido Benimaru" ]; then
echo "${input_name} is a fighter who wields flames."
elif [ "$input_name" = "Daimon Goro" ]; then
echo "${input_name} is the strongest judoka."
else
echo "${input_name} is not a member of the Kusanagi team."
fi
echo ""
echo "=== Empty string check ==="
# Use -z to check whether a string is empty
fighter=""
if [ -z "$fighter" ]; then
echo "No fighter name was entered."
else
echo "Fighter name: ${fighter}"
fi
echo ""
echo "=== String inequality ==="
rival="Yagami Iori"
# Use != to check whether strings differ
if [ "$rival" != "Kusanagi Kyo" ]; then
echo "${rival} is the rival of Kusanagi Kyo."
fi
$ chmod +x kof_string_compare.sh $ ./kof_string_compare.sh === Exact string match === Kusanagi Kyo is the leader of the Kusanagi team. === Empty string check === No fighter name was entered. === String inequality === Yagami Iori is the rival of Kusanagi Kyo.
kof_numeric_compare.sh
#!/bin/bash
# -----------------------------------------------
# Demonstrates numeric comparison with if
# using KOF characters
# -----------------------------------------------
# -----------------------------------------------
# Set each character's power level into variables
# -----------------------------------------------
declare -A power
power["Kusanagi Kyo"]=9500
power["Yagami Iori"]=9200
power["Leona"]=8800
power["Terry Bogard"]=9000
power["Mai Shiranui"]=7500
target="Kusanagi Kyo"
score=${power[$target]}
echo "=== Numeric comparison ==="
echo "${target} power level: ${score}"
echo ""
# Use -ge (greater than or equal) to determine rank by power level
if [ "$score" -ge 9500 ]; then
echo "Rank: S class (Overlord)"
elif [ "$score" -ge 9000 ]; then
echo "Rank: A class (Legendary Fighter)"
elif [ "$score" -ge 7000 ]; then
echo "Rank: B class (Advanced)"
else
echo "Rank: C class (Intermediate)"
fi
echo ""
echo "=== Rank for all characters ==="
# Determine rank for all characters using a for loop
for chara in "${!power[@]}"; do
val=${power[$chara]}
if [ "$val" -ge 9500 ]; then
rank="S"
elif [ "$val" -ge 9000 ]; then
rank="A"
elif [ "$val" -ge 7000 ]; then
rank="B"
else
rank="C"
fi
echo " ${chara}: ${val} (Rank ${rank})"
done
$ chmod +x kof_numeric_compare.sh $ ./kof_numeric_compare.sh === Numeric comparison === Kusanagi Kyo power level: 9500 Rank: S class (Overlord) === Rank for all characters === Kusanagi Kyo: 9500 (Rank S) Yagami Iori: 9200 (Rank A) Leona: 8800 (Rank B) Terry Bogard: 9000 (Rank A) Mai Shiranui: 7500 (Rank B)
kof_file_test.sh
#!/bin/bash
# -----------------------------------------------
# Demonstrates file test operators using
# KOF character data files
# -----------------------------------------------
# -----------------------------------------------
# Create test files and directories
# -----------------------------------------------
# Create a working directory
work_dir="./kof_data"
mkdir -p "$work_dir"
# Create character data files
echo "Name: Kusanagi Kyo, Team: Kusanagi, Move: Yami Barai" > "${work_dir}/kusanagi_kyo.txt"
echo "Name: Yagami Iori, Team: Yagami, Move: Yasakani no Magatama" > "${work_dir}/yagami_iori.txt"
touch "${work_dir}/empty_fighter.txt" # Create an empty file (size 0)
echo "=== File tests ==="
echo ""
# Use -f to check whether a file exists
target_file="${work_dir}/kusanagi_kyo.txt"
if [ -f "$target_file" ]; then
echo "[OK] ${target_file} is a regular file."
else
echo "[NG] ${target_file} was not found."
fi
echo ""
# Use -d to check whether a path is a directory
if [ -d "$work_dir" ]; then
echo "[OK] ${work_dir} is a directory."
fi
echo ""
# Use -s to check whether a file is non-empty
echo "=== File content check ==="
for f in "${work_dir}"/*.txt; do
if [ -s "$f" ]; then
echo " [data] $(basename $f): has content"
else
echo " [empty] $(basename $f): no content"
fi
done
echo ""
# Use -r and -w to check read/write permissions
echo "=== Permission check ==="
check_file="${work_dir}/kusanagi_kyo.txt"
if [ -r "$check_file" ] && [ -w "$check_file" ]; then
echo "${check_file} is readable and writable."
fi
# Remove the working directory and clean up
rm -rf "$work_dir"
echo ""
echo "Cleanup complete."
$ chmod +x kof_file_test.sh $ ./kof_file_test.sh === File tests === [OK] ./kof_data/kusanagi_kyo.txt is a regular file. [OK] ./kof_data is a directory. === File content check === [empty] empty_fighter.txt: no content [data] kusanagi_kyo.txt: has content [data] yagami_iori.txt: has content === Permission check === ./kof_data/kusanagi_kyo.txt is readable and writable. Cleanup complete.
Comparing [ ] and [[ ]]
| Feature | [ ] (test) | [[ ]] (bash extension) |
|---|---|---|
| POSIX compliance | Compliant (works in sh). | bash / zsh only. Not available in sh. |
| AND / OR | Use -a / -o (not recommended), or write separate [ ] && [ ] tests. | && / || can be used directly. |
| Pattern matching | Not supported. | == supports glob patterns (e.g., *). |
| Regular expressions | Not supported. | =~ supports POSIX extended regular expressions. |
| Word splitting | Word splitting occurs if variables are not quoted. | Word splitting does not occur even without quoting (safer). |
< / > | Interpreted as redirection; must be escaped as \< / \>. | Used directly as lexicographic string comparison operators. |
Summary
The if statement in Shell Script branches based on a command's exit status (0 is true), chains additional conditions with elif, and closes with fi. Conditions are evaluated using the POSIX-compliant [ ] (equivalent to test) or the bash-extended [[ ]]. For string comparison, use =, !=, -z, and -n. For numeric comparison, use -eq, -ne, -lt, -le, -gt, and -ge. For file tests, use -f, -d, -e, -s, and others. Choose [ ] when portability matters, or [[ ]] when writing bash-specific scripts where readability and safety are priorities. For combining multiple conditions, [[ condA && condB ]] is recommended. See also for loop for combining if with loops.
If you find any errors or copyright issues, please contact us.