Bash if Statements: Conditional Logic in Shell Scripts
Learn Bash if, elif, and else statements, test syntax, numeric comparisons, input validation, and file and directory checks.
A Bash if statement evaluates a condition and chooses which command block to run. This lets a script make decisions instead of always executing the same commands. Common uses include validating user input, checking whether files exist, controlling script flow, and responding to system state.
A condition is a conditional expression: a test whose result determines which branch runs. In shell scripting, commands communicate results through an exit status. Status 0 conventionally means success, or true. Any nonzero status means failure, or false. An if statement runs its successful branch when the condition command returns status 0.
Basic Bash if Syntax
The basic structure uses if, then, an optional else, and fi. The keyword fi closes the block; it is if spelled in reverse.
#!/bin/bash
if [ condition ]; then
commands_when_true
else
commands_when_false
fi
In this multiline form, then follows the test on the same line after a semicolon. It can also go on the next line:
if [ condition ]
then
commands_when_true
else
commands_when_false
fi
The semicolon is a command separator. If then remains on the same line as the test, write ; before it. Commands in only the selected branch run after Bash evaluates the condition.
Branching Keywords
The test Command and Bracket Syntax
Bash provides the test command for evaluating file, string, and numeric conditions. The form [ ... ] is another command form of test; the brackets are not merely punctuation.
test "$age" -ge 18
[ "$age" -ge 18 ]
These two commands express the same test. Whitespace is mandatory after the opening bracket and before the closing bracket. The closing bracket is an argument required by the bracket form.
# Correct
[ "$file" -e ]
# Incorrect: missing spaces
["$file" -e]
# Correct file test
[ -e "$file" ]
Quote variable expansions in tests by default, especially when values can be empty or come from users. Quoting prevents spaces and shell metacharacters in a value from being interpreted as separate words or syntax.
Reading Input and Using Variables
A variable stores a named shell value. Assign without spaces around the equals sign, and expand the value with a leading dollar sign. The Bash builtin read collects input into a variable.
#!/bin/bash
printf "Enter your age: "
read -r age
if [ "$age" -ge 18 ]; then
echo "Access allowed."
else
echo "Access denied."
fi
Here, read -r age stores the response in age, and "$age" supplies that value to the numeric test.
Numeric Comparisons
Numeric operators compare integer values, not text. Use them only after ensuring that the input is a valid integer.
Validate Before an Integer Test
An empty or non-numeric value can cause an integer-expression error. Check the input before using -ge, -le, or another numeric operator.
#!/bin/bash
printf "Enter your age: "
read -r age
if [[ ! "$age" =~ ^[0-9]+$ ]]; then
echo "Please enter a whole number."
elif [ "$age" -ge 18 ]; then
echo "Access allowed."
else
echo "Access denied."
fi
The expression with [[ ... ]] checks that the value contains one or more digits. It rejects blank input and values containing letters or other characters before the bracket-form numeric test runs.
if, elif, and else Branches
Use elif to add mutually exclusive alternatives. Bash evaluates conditions from top to bottom and runs the first branch whose condition succeeds. Once a branch runs, later conditions are not evaluated. The else branch is the fallback when no preceding condition succeeds.
#!/bin/bash
printf "Enter your age: "
read -r age
if [[ ! "$age" =~ ^[0-9]+$ ]]; then
echo "Invalid age. Enter a whole number."
elif [ "$age" -lt 13 ]; then
echo "You are in the younger range."
elif [ "$age" -le 64 ]; then
echo "You are in the middle range."
else
echo "You are in the older range."
fi
The order matters. An age of 10 matches the first numeric range and stops there. An age of 40 fails the first range, succeeds at -le 64, and never reaches else. Design overlapping ranges carefully so their boundaries produce the intended result.
File and Directory Conditionals
File tests evaluate a pathname. Store the pathname in a variable and quote its expansion so paths containing spaces remain one argument.
Checking Whether a Path Exists
#!/bin/bash
file="/tmp/report.txt"
if [ -e "$file" ]; then
echo "The path exists: $file"
else
echo "The path does not exist: $file"
fi
-e answers whether a path exists. It does not say whether the path is a regular file or a directory. Use -f and -d when the type matters.
#!/bin/bash
path="project data"
if [ -f "$path" ]; then
echo "This is a regular file."
elif [ -d "$path" ]; then
echo "This is a directory."
else
echo "The path is missing or another type."
fi
Checking Permissions
#!/bin/bash
file="script.sh"
if [ -r "$file" ]; then
echo "The path is readable."
fi
if [ -w "$file" ]; then
echo "The path is writable."
fi
if [ -x "$file" ]; then
echo "The path has execute permission."
fi
Each if is independent, so more than one permission message can be printed. A test describes the permissions available to the current process; it is not a guarantee that a later operation will succeed under every system condition.
Complete Script Examples
Minimum-Age Access Check
#!/bin/bash
printf "Enter your age: "
read -r age
if [[ ! "$age" =~ ^[0-9]+$ ]]; then
echo "Invalid input. Enter a whole number."
elif [ "$age" -ge 21 ]; then
echo "You meet the minimum age."
else
echo "You are below the minimum age."
fi
Save a script as age-check.sh. Run it with bash age-check.sh, or make it executable and run it directly:
chmod +x age-check.sh
./age-check.sh
File Existence and Type Check
#!/bin/bash
printf "Enter a path: "
read -r file
if [ -e "$file" ]; then
if [ -f "$file" ]; then
echo "The path exists and is a regular file."
elif [ -d "$file" ]; then
echo "The path exists and is a directory."
else
echo "The path exists but is another type."
fi
else
echo "The path does not exist."
fi
Correctness Rules and Troubleshooting
- Missing bracket spaces: Write
[ condition ], not[condition]. The shell reports a malformed test or a missing]when the required whitespace is absent. - Syntax error near then: Put
thenon its own line, or useif [ condition ]; then. Also check that the test is correctly closed. - Integer expression error: Validate blank and non-numeric input before applying numeric operators. Quote expansions such as
"$age". - Incorrect path result: Quote path variables, for example
[ -e "$file" ], especially when a pathname can contain spaces. - Wrong elif branch: Bash selects the first successful condition. Reorder overlapping ranges and make boundary operators explicit.
- Script fails before testing conditions: Use a valid shebang, such as
#!/bin/bash, and run it withbash script.shor execute it afterchmod +x script.sh. - Spelling and spacing: Shell keywords, test operators, brackets, and delimiters must be spelled exactly and separated as required.
Logical Next Steps
After basic branches work, extend conditions with compound logic. The && operator represents logical AND, || represents logical OR, and ! negates a condition.
if [ -f "$file" ] && [ -r "$file" ]; then
echo "A readable regular file was found."
fi
if [ -z "$name" ] || [ "$name" = "quit" ]; then
echo "No usable name was supplied."
fi
For selecting among many fixed patterns or values, investigate Bash case statements. Also test scripts with expected inputs and unexpected inputs: blank values, non-numeric values, paths with spaces, missing paths, and boundary numbers.
Summary
- An
ifstatement evaluates a command or test and runs the selected command block. test conditionand[ condition ]are equivalent forms; bracket spacing is required.- Use
-eq,-ne,-lt,-le,-gt, and-gefor integer comparisons. - Validate user input before numeric comparisons.
- Use
eliffor ordered alternatives andelseas the fallback. - Use
-e,-f, and-dto distinguish existence, regular files, and directories; use-r,-w, and-xfor permissions. - Start Bash scripts with
#!/bin/bashand test both normal and unexpected inputs.