Checking that files exist, arguments are present or values match is the core of every script.
if runs a command and takes the branch when its exit status is 0. The command is usually a test:
[ ... ]is the classic POSIXtestcommand (it is literally a program named[), so it needs spaces around brackets and quotes around variables.[[ ... ]]is a bash keyword: it does not word-split variables, supports&&and||inside,==with glob patterns and=~with regular expressions. Prefer it in bash scripts.(( ... ))evaluates arithmetic and succeeds when the result is non-zero.
Common tests: strings -z (empty), -n (non-empty), ==, !=; numbers -eq -ne -lt -le -gt -ge (or < and > inside (( ))); files -e exists, -f regular file, -d directory, -r -w -x permissions, -s non-empty.
The syntax is if cond; then ...; elif cond; then ...; else ...; fi. Any command works as a condition: if grep -q error log.txt; then is idiomatic and faster than capturing output.
Watch out: inside [[ ]], < and > compare strings alphabetically, so [[ 10 < 9 ]] is true. Use -lt or (( )) for numbers. After an =~ match, captured groups are in the BASH_REMATCH array.
Example
f=/etc/passwd
if [[ -d $f ]]; then
echo "$f is a directory"
elif [[ -f $f && -r $f ]]; then
echo "$f is a readable file" # this branch runs
else
echo "$f: not found"
fi
name=""
[[ -z $name ]] && echo "name is empty" # name is empty
n=7
if (( n > 5 )); then echo "big"; fi # big
if [ "$n" -lt 10 ]; then echo "single digit"; fi # single digit
s="report.csv"
[[ $s == *.csv ]] && echo "CSV file" # CSV file
[[ $s =~ ^([a-z]+)\. ]] && echo "${BASH_REMATCH[1]}" # report
[[ 10 < 9 ]] && echo "string comparison!" # string comparison!Remember
- if takes the branch when the condition command exits 0
- Prefer [[ ]] for strings and files, (( )) for numbers
- Any command can be a condition: if grep -q ...; then
Watch out for
- Comparing numbers with < or == inside [[ ]], which compares them as strings.