Conditionals
Conditional execution based on command exit status or test expressions.
Source: src/scripting/control_flow.f90:129-272, src/ast/evaluator_simple_real.f90:2349-2495
If Statements
Basic Syntax
if condition; then
commands
fi
With Elif and Else
if condition1; then
commands
elif condition2; then
commands
else
commands
fi
Condition Types
Conditions can be:
- Test expressions -
[ ... ]or[[ ... ]] - Commands - exit status 0 = true, non-zero = false
# Test expression
if [[ -f "$file" ]]; then
echo "File exists"
fi
# Command as condition
if grep -q "pattern" file.txt; then
echo "Found"
fi
# Negated condition
if ! command; then
echo "Command failed"
fi
Evaluation
The condition is evaluated by evaluate_condition() (control_flow.f90:25). When the condition evaluates to true (exit status 0), the then-block executes. Otherwise, elif conditions are checked in order until one matches, or the else-block executes.
# Multiple conditions
if [[ $x -gt 10 ]]; then
echo "x > 10"
elif [[ $x -gt 5 ]]; then
echo "5 < x <= 10"
elif [[ $x -gt 0 ]]; then
echo "0 < x <= 5"
else
echo "x <= 0"
fi
One-Liners
# Compact form
if [[ $debug ]]; then echo "Debug on"; fi
# Using && and ||
[[ -f file ]] && echo "exists" || echo "missing"
Case Statements
Pattern-based branching with glob matching.
Source: src/scripting/control_flow.f90:1221-1419
Basic Syntax
case word in
pattern1) commands ;;
pattern2) commands ;;
esac
Multiple Patterns
Use | to match multiple patterns:
case $answer in
y|Y|yes|Yes|YES)
echo "Affirmative"
;;
n|N|no|No|NO)
echo "Negative"
;;
*)
echo "Unknown: $answer"
;;
esac
Glob Patterns
Case patterns support full glob syntax:
case $file in
*.txt)
echo "Text file"
;;
*.sh)
echo "Shell script"
;;
[0-9]*)
echo "Starts with digit"
;;
???)
echo "Three characters"
;;
*)
echo "Other"
;;
esac
Character Classes
case $char in
[[:alpha:]])
echo "Letter"
;;
[[:digit:]])
echo "Digit"
;;
[[:space:]])
echo "Whitespace"
;;
esac
First Match Wins
Once a pattern matches, subsequent patterns are skipped:
case "abc" in
a*) echo "Matches a*" ;; # This matches
abc) echo "Matches abc" ;; # Never reached
esac
Exit Status
- Returns exit status of last executed command
- Returns 0 if no pattern matched
Pattern Matching Details
Pattern matching uses pattern_matches_no_dotfile_check() from the glob module. Multi-pattern matching is handled by check_multi_pattern() (control_flow.f90:1376), which splits on | and checks each pattern.
Combining Conditions
Logical AND
if [[ -f "$file" ]] && [[ -r "$file" ]]; then
echo "File exists and is readable"
fi
# Or within [[ ]]
if [[ -f "$file" && -r "$file" ]]; then
echo "File exists and is readable"
fi
Logical OR
if [[ -z "$var" ]] || [[ "$var" == "default" ]]; then
var="fallback"
fi
Negation
if ! [[ -d "$dir" ]]; then
mkdir "$dir"
fi
# Within [[ ]]
if [[ ! -d "$dir" ]]; then
mkdir "$dir"
fi
Nested Conditionals
if [[ -d "$path" ]]; then
if [[ -w "$path" ]]; then
echo "Writable directory"
else
echo "Read-only directory"
fi
elif [[ -f "$path" ]]; then
echo "It's a file, not a directory"
else
echo "Path doesn't exist"
fi
Common Patterns
Default Values
if [[ -z "$CONFIG" ]]; then
CONFIG="/etc/myapp/config"
fi
# Or more concisely
: "${CONFIG:=/etc/myapp/config}"
File Type Dispatch
case $(file -b --mime-type "$1") in
text/*)
cat "$1"
;;
image/*)
display "$1"
;;
application/pdf)
evince "$1"
;;
*)
echo "Unknown type"
;;
esac
Option Parsing
while [[ $# -gt 0 ]]; do
case $1 in
-v|--verbose)
verbose=1
shift
;;
-o|--output)
output="$2"
shift 2
;;
--)
shift
break
;;
-*)
echo "Unknown option: $1" >&2
exit 1
;;
*)
break
;;
esac
done