Linux online course

Bash if Statements: Conditional Logic in Linux Shell Scripts

Learn Bash if, then, else, and elif statements with numeric comparisons, file tests, variables, examples, and troubleshooting tips.

What conditional execution means

Conditional execution means running a command block only when a tested condition succeeds or fails. A Bash if statement is a control structure that evaluates a condition and chooses which commands to run.

Bash determines whether a condition succeeded by examining the command's exit status. An exit status of 0 means success, so Bash treats the condition as true. A nonzero exit status means failure, so Bash treats the condition as false.

Conditional logic is useful when a script needs to validate user input, check whether a file exists, or select different program behavior based on a value.

This lesson assumes familiarity with the Bash shell, commands, variables, and basic Linux files and permissions.

Basic Bash if syntax

The standard multiline structure is:

if [ condition ]; then
  commands_when_true
else
  commands_when_false
fi

then begins the command block that runs when the condition succeeds. else begins the fallback block that runs when the condition fails. fi closes the entire if structure; it is if written backward.

then must be separated from the condition by either a newline or a semicolon. Both forms below are valid:

if [ -f "report.txt" ]
then
  echo "A regular file was found"
fi
if [ -f "report.txt" ]; then
  echo "A regular file was found"
fi

A complete one-line form is also valid when commands are separated correctly:

if [ -f "report.txt" ]; then echo "Found"; else echo "Missing"; fi

The test command and bracket syntax

[ condition ] is a command form of the Bash test command. The brackets are not merely punctuation built into the if statement. The opening bracket is the command name, and the closing bracket is an argument required by that command.

Spaces are required immediately inside the brackets. Write:

if [ "$age" -ge 21 ]; then
  echo "Eligible"
fi

Do not write [$age -ge 21] or [ "$age" -ge 21] without the closing space. Without the required argument boundaries, Bash cannot parse the test correctly.

Bash also provides the alternative form [[ condition ]]. It is a Bash conditional construct with more shell-specific behavior and safer handling of several pattern and string operations. Use [ condition ] when learning the traditional test command form, and use [[ condition ]] when you specifically need its Bash features.

Variables and safe input handling

The read command accepts input and stores it in a shell variable. A variable reference such as $age undergoes variable expansion: Bash replaces the reference with the value stored in age.

read -r -p "How old are you? " age
echo "You entered: $age"

Quote variable expansions in tests unless you have a specific reason not to. Quoting keeps an empty value or a path containing spaces from being split into separate arguments.

if [ "$age" -ge 21 ]; then
  echo "Eligible"
fi

An empty value or nonnumeric text can cause an integer expression error when used with numeric operators. Validate input before performing numeric comparisons when the value comes from a user or another untrusted source.

Numeric comparison operators

With the traditional [ ] test form, numeric comparisons use integer-specific operators. These are different from the string comparison operators used for text.

OperatorMeaningExample condition
-eqEqual to[ "$count" -eq 3 ]
-neNot equal to[ "$count" -ne 0 ]
-ltLess than[ "$age" -lt 18 ]
-leLess than or equal to[ "$age" -le 21 ]
-gtGreater than[ "$score" -gt 90 ]
-geGreater than or equal to[ "$age" -ge 21 ]

These operators perform numeric comparison for integer values. Do not confuse them with string comparisons. For example, -eq is used for integer equality in a bracket test, while text comparisons use different syntax such as =.

Two-way branching with if and else

This script reads an age and prints one result for an eligible age and another for an ineligible age:

#!/bin/bash
read -r -p "How old are you? " age

if [ "$age" -ge 21 ]; then
  echo "Eligible"
else
  echo "Not eligible"
fi

The evaluation order is:

  1. Bash runs the test [ "$age" -ge 21 ].
  2. If the test returns status 0, Bash runs the then block and skips the else block.
  3. If the test returns a nonzero status, Bash skips the then block and runs the else block.
  4. fi ends the structure.

Multiple conditions with elif

elif means “else if.” It adds another test after an earlier if or elif condition fails. Bash checks branches from top to bottom, and the first successful branch runs. Remaining branches are skipped.

#!/bin/bash
read -r -p "How old are you? " age

if [ "$age" -le 21 ]; then
  echo "Young range"
elif [ "$age" -ge 60 ]; then
  echo "Older range"
else
  echo "Middle range"
fi

Here, ages less than or equal to 21 match the first branch. If that test fails, Bash checks whether the age is greater than or equal to 60. The final else is the fallback for values that matched neither test, which produces the middle-range result.

Branch order matters. A broad condition placed before a narrower condition can make the later branch unreachable. Arrange boundaries deliberately and ensure ranges do not overlap unintentionally.

Structure partWhen it is evaluated or runOutcome
if conditionEvaluated firstStarts the selection process
then blockRun when the preceding condition succeedsIts commands execute and later tests are skipped
elif conditionEvaluated only if earlier conditions failedProvides another possible branch
else blockRun when all preceding conditions failProvides the fallback behavior
fiRead after the selected block finishesEnds the if structure

File test operators

A file test operator checks a filesystem object's existence, type, or permissions. Quote a pathname variable, especially when it may contain spaces.

OperatorWhat it testsExample condition
-eThe path exists[ -e "$path" ]
-fThe path exists and is a regular file[ -f "$path" ]
-dThe path exists and is a directory[ -d "$path" ]
-xThe path has executable permission[ -x "$path" ]
-wThe path has writable permission[ -w "$path" ]
-rThe path has readable permission[ -r "$path" ]

-e only asks whether a path exists. It does not say whether the path is a regular file or a directory. Use -f for a regular file and -d for a directory.

Check whether a path exists

#!/bin/bash
file="test_file"

if [ -e "$file" ]; then
  echo "File exists: $file"
else
  echo "File does not exist: $file"
fi

Check file type and access

#!/bin/bash
read -r -p "Enter a path: " path

if [ -d "$path" ]; then
  echo "This path is a directory"
elif [ -f "$path" ]; then
  echo "This path is a regular file"
  if [ -r "$path" ] && [ -w "$path" ]; then
    echo "It is readable and writable"
  elif [ -r "$path" ]; then
    echo "It is readable but not writable"
  elif [ -w "$path" ]; then
    echo "It is writable but not readable"
  else
    echo "It is neither readable nor writable"
  fi
else
  echo "The path is not a regular file or directory"
fi

The nested tests demonstrate that file type and access are separate questions. A path can exist without being a regular file, and a regular file can have different read, write, or execute permissions.

For more background, see how to determine file type and the Linux file structure.

Writing and running Bash scripts

A shebang is the first-line interpreter declaration in an executable script. For Bash, the usual declaration is #!/bin/bash.

#!/bin/bash
if [ -f "settings.conf" ]; then
  echo "Configuration found"
else
  echo "Configuration missing"
fi

Save the content in a file such as check.sh. Grant execute permission and run it from the current directory:

chmod +x check.sh
./check.sh

You can also invoke the script through Bash directly. This does not require changing the executable permission:

bash check.sh

Common syntax and logic pitfalls

  • Missing spaces around brackets: Use [ "$age" -ge 21 ], not ["$age" -ge 21]. The spaces separate arguments to the test command.
  • Missing separator before then: On one line, write if [ condition ]; then. Alternatively, put then on the next line.
  • Omitted fi: Every if structure needs a closing fi. Otherwise Bash may report an unexpected end-of-file error.
  • Unquoted expansions: Write [ -e "$file" ], not [ -e $file ]. An empty value or a path containing spaces can change the arguments passed to the test command.
  • Incorrect branch ordering: Bash stops at the first matching branch. A broad earlier condition can prevent a later elif from ever running.
  • Confusing string and numeric syntax: Use -eq, -lt, and -ge for integer comparisons with [ ]. Text comparisons use different operators and should not be substituted casually.
  • Invalid numeric input: Empty or nonnumeric input can produce an integer expression error. Validate user input before using numeric operators.

Troubleshooting if statements

ProblemLikely causeFix
The shell reports an error near then.The condition and then are on one line without a semicolon, or then is missing.Use a newline before then or write if [ condition ]; then.
The test reports a missing bracket or unexpected operator.Spaces were omitted after [ or before ].Write whitespace around the test expression, such as [ "$age" -ge 21 ].
A numeric comparison produces an integer expression error.The variable is empty or contains nonnumeric text.Validate the input before applying numeric operators.
A file test fails for a path containing spaces.The file variable was expanded without quotes.Use [ -e "$file" ].
An elif branch never runs.An earlier condition already matches the same values.Reorder the tests and check for overlapping ranges.
The script ends with an unexpected end-of-file error.The structure has no closing fi.Add fi after the final branch.

Practice checklist

  1. Write an if/else script that tests whether a number is at least 21.
  2. Extend it with elif to classify younger, middle-range, and older input.
  3. Store a pathname in a variable and test it with -e, -f, and -d.
  4. Add -r and -w checks for a regular file.
  5. Run the script once with bash script.sh and once after using chmod +x script.sh and ./script.sh.