File and String Tests
Prerequisites: Conditionals: if and tests
Scripts constantly check whether files exist, whether a variable is
empty, and so on. [[ ]] has operators for all of these.
File tests
mkdir reports
echo "data" > data.csv
touch empty.txt
[[ -e data.csv ]] && echo "data.csv exists"
[[ -f data.csv ]] && echo "data.csv is a regular file"
[[ -d reports ]] && echo "reports is a directory"
[[ -s empty.txt ]] || echo "empty.txt is empty"
[[ -r data.csv ]] && echo "data.csv is readable"
[[ -e nope.txt ]] || echo "nope.txt doesn't exist"
data.csv exists
data.csv is a regular file
reports is a directory
empty.txt is empty
data.csv is readable
nope.txt doesn't exist
| Test | True if... |
|---|---|
-e |
the path exists |
-f |
it's a regular file |
-d |
it's a directory |
-s |
it exists and isn't empty |
-r -w -x |
readable / writable / executable |
a -nt b |
file a is newer than b |
String tests
empty=""
name="Ada"
[[ -z $empty ]] && echo "empty is empty"
[[ -n $name ]] && echo "name is set to '$name'"
[[ $name =~ ^[A-Z][a-z]+$ ]] && echo "name looks like a capitalized word"
empty is empty
name is set to 'Ada'
name looks like a capitalized word
-z— the string is empty;-n— it isn't.=~matches a regular expression (Bash only). Try patterns in the Regex Tester.
A guard at the top of a script
cat > process.sh <<'EOF'
input=$1
if [[ -z $input ]]; then
echo "Usage: process.sh <file>" >&2
exit 1
fi
if [[ ! -f $input ]]; then
echo "Error: '$input' is not a file" >&2
exit 1
fi
echo "Processing $input ($(wc -l < "$input") lines)"
EOF
printf 'a\nb\n' > list.txt
bash process.sh missing.txt
bash process.sh list.txt
Error: 'missing.txt' is not a file
Processing list.txt (2 lines)
Checking inputs first, with clear messages, makes scripts far easier to use and debug.