Thuta Learning
IntermediateDevOps & Toolsbeginner

Working with Files and Directories in Scripts

What you'll walk away with

  • Explain the core ideas behind Working with Files and Directories in Scripts
  • Run the sample code and verify its output
  • Apply the technique correctly to the Tutorial Platform and production scenarios

Build the mental model

A script that touches the filesystem should never assume a file or directory is in the state it expects, because the environment around a script is never fully under its control — a disk can fill up, a path can be missing or renamed, permissions can be wrong, or a previous run of the same script could have left things in an unexpected state. Bash gives you a family of test operators for exactly this reason: -e checks whether something exists at all, -f narrows that to a regular file, -d to a directory, and -r, -w, -x check read, write, and execute permission respectively — each returning true or false as an exit status you can use directly inside [[ ]] before acting. Just as important as checking a file's state is deciding how to enumerate a set of files in the first place. A plain glob like *.txt is simple, predictable, and usually all you need for a flat directory, but it only expands relative to the current shell context and does not recurse into subdirectories. The find command is considerably more powerful: it can search recursively, filter by type with -type, filter by name pattern, and — critically — handle filenames containing spaces or unusual characters correctly when combined with a null-safe read loop, situations where a glob alone would silently misbehave.

Connect it to a real scenario

Think of a backup script that needs to check whether a target directory exists before writing into it, create a safe scratch space instead of hardcoding a path like /tmp/mydata that another process could collide with, and confirm each operation actually succeeded before deleting anything. This lesson's code walks through that exact sequence: work_dir=$(mktemp -d) creates a directory with a guaranteed-unique name, sidestepping any race condition or collision that a hardcoded temp path invites. Before treating work_dir as usable, the script verifies it with [[ -d "$work_dir" ]], confirms report.txt specifically is a regular file (not a directory or something stranger) with -f, and checks both -r and -w together to make sure it is actually readable and writable before relying on it — combined inside a single [[ ]] with &&, both conditions must hold. It also demonstrates the negative case, [[ ! -e "$work_dir/missing.txt" ]], confirming a file genuinely does not exist rather than just assuming so. For enumeration, the glob for file in "$work_dir"/*.txt is simple and sufficient for a flat directory, while the find version — find "$work_dir" -maxdepth 1 -type f -name "*.txt" | sort | while read -r file — shows the more robust pattern you'd reach for once depth, filtering, or predictable ordering matters. Finally, checking [[ $? -eq 0 ]] after rm -rf is the same discipline applied to cleanup: never assume a destructive operation succeeded just because it ran.

Try the working example

bash
#!/bin/bash
work_dir=$(mktemp -d)

# Create some files inside the temp directory
touch "$work_dir/report.txt"
touch "$work_dir/notes.txt"
mkdir "$work_dir/archive"

if [[ -d "$work_dir" ]]; then
  echo "work_dir exists and is a directory"
fi

if [[ -f "$work_dir/report.txt" ]]; then
  echo "report.txt exists and is a regular file"
fi

if [[ -r "$work_dir/report.txt" && -w "$work_dir/report.txt" ]]; then
  echo "report.txt is readable and writable"
fi

if [[ ! -e "$work_dir/missing.txt" ]]; then
  echo "missing.txt does not exist"
fi

echo "Looping over .txt files with a glob:"
for file in "$work_dir"/*.txt; do
  echo "Found: $(basename "$file")"
done

echo "Looping over files with find:"
find "$work_dir" -maxdepth 1 -type f -name "*.txt" | sort | while read -r file; do
  echo "Found via find: $(basename "$file")"
done

rm -rf "$work_dir"
if [[ $? -eq 0 ]]; then
  echo "Cleanup succeeded"
fi
You should see
Running this script prints:

work_dir exists and is a directory
report.txt exists and is a regular file
report.txt is readable and writable
missing.txt does not exist
Looping over .txt files with a glob:
Found: notes.txt
Found: report.txt
Looping over files with find:
Found via find: notes.txt
Found via find: report.txt
Cleanup succeeded

5-minute try-it

Write a script that creates a temporary directory with mktemp -d, checks whether it is writable, creates two files with different extensions inside it, then loops over only the files matching one extension and prints their names before cleaning everything up.

One important caution

Looping over a glob like *.txt without checking whether it actually matched anything — if no file matches, bash passes the literal unexpanded string "*.txt" into the loop

Assuming a command like cp or mv succeeded just because it ran, instead of checking its exit status ($?) before proceeding to delete the original file

GNU Bash Manual: Bash Conditional ExpressionsBash / Shell Scripting

Easy traps

  • Looping over a glob like *.txt without checking whether it actually matched anything — if no file matches, bash passes the literal unexpanded string "*.txt" into the loop
  • Assuming a command like cp or mv succeeded just because it ran, instead of checking its exit status ($?) before proceeding to delete the original file
  • Validate sample code in a local or test environment before applying it to a production system.

Exercise

Write a script that creates a temporary directory with mktemp -d, checks whether it is writable, creates two files with different extensions inside it, then loops over only the files matching one extension and prints their names before cleaning everything up.

You'll know it worked when: Running this script prints: work_dir exists and is a directory report.txt exists and is a regular file report.txt is readable and writable missing.txt does not exist Looping over .txt files with a glob: Found: notes.txt Found: report.txt Looping over files with find: Found via find: notes.txt Found via find: report.txt Cleanup succeeded

Working with Files and Directories in Scripts | Thuta Learning