03 File and Directory Operations

Learning objectives

  • Create files and directories.
  • Copy, move, rename, and remove files.
  • Inspect file type and detailed file status.

Command overview

CommandPurposeMeaningBasic usageExample
touchCreate an empty file or update timestampsCreates a missing file; otherwise updates its timestamptouch file_nametouch notes.txt
mkdirCreate a directoryMake directorymkdir [options] directory_namemkdir -p logs/2026
cpCopy a file or directoryCopies a source to a destinationcp source destinationcp a.txt b.txt
mvMove or renameMoves a source to a destination and can rename itmv source destinationmv old.txt new.txt
rmRemove a file or directoryRemoves a specified pathrm filerm old.txt
fileDetermine file typeIdentifies a format from its contentsfile filefile app.log
statInspect detailed file statusShows metadata such as size, permissions, and timestat filestat app.log

Common scenarios

The following complete controlled lab does not rely on an existing directory named project. It creates a unique temporary directory, verifies the absolute path and ownership, then creates, copies, moves, and removes one explicit file:

if [ "$(id -u)" -eq 0 ]; then
  printf 'do not run this lab as root\n' >&2
  exit 1
fi
 
lab_root=$(realpath -e -- "${TMPDIR:-/tmp}") || exit 1
home_real=$(realpath -e -- "${HOME:?HOME is required}") || exit 1
current_real=$(pwd -P)
paths_overlap_tree() {
  if [ "$1" = '/' ] || [ "$2" = '/' ]; then
    return 0
  fi
  case "$1/" in "$2/"*) return 0 ;; esac
  case "$2/" in "$1/"*) return 0 ;; esac
  return 1
}
if [ "$lab_root" = '/' ] \
    || paths_overlap_tree "$lab_root" "$home_real" \
    || paths_overlap_tree "$lab_root" "$current_real"; then
  printf 'unsafe lab root overlaps home or working tree: %s\n' "$lab_root" >&2
  exit 1
fi
 
work=$(mktemp -d "$lab_root/file-ops.XXXXXX") || exit 1
work_real=$(realpath -e -- "$work") || exit 1
case "$work_real" in
  "$lab_root"/file-ops.*) ;;
  *) printf 'unexpected work path: %s\n' "$work_real" >&2; exit 1 ;;
esac
if [ ! -O "$work" ] || [ -L "$work" ]; then
  printf 'work ownership or symlink check failed\n' >&2
  exit 1
fi
 
cd -- "$work_real" || exit 1
[ "$(pwd -P)" = "$work_real" ] || exit 1
mkdir -p -- project/data/raw project/data/processed project/logs
touch -- project/README.md
cp -- project/README.md project/README.bak.md
cp -R -- project/data project/data_backup
mv -- project/README.bak.md project/backup.md
mv -- project/backup.md project/logs/
 
target=$(realpath -e -- "$work_real/project/logs/backup.md") || exit 1
case "$target" in
  "$work_real"/project/logs/backup.md) ;;
  *) printf 'unexpected target: %s\n' "$target" >&2; exit 1 ;;
esac
printf 'delete=%s\n' "$target"
rm -- "$target"
file -- project/README.md
stat -- project/README.md
find . -maxdepth 3 -print

The recursive-deletion signature is for reference only: rm -r -- "$directory". This course does not offer directly copyable rm -rf because it bypasses some interactive and missing-file warnings. Its default --preserve-root gives special protection only to /; it does not protect a home directory, mount point, or incorrect variable. Keep the lab directory for inspection; do not remove it recursively automatically.

Notes for beginners

  • rm usually does not move files to a recycle bin, so confirm the path before execution.
  • rm -rf is extremely dangerous. Never use it for /, ~, or a path assembled from an empty variable.
  • cp -R is the portable POSIX option for copying a directory. GNU -r is common, but scripts should check the target platform.
  • mv both moves and renames; when the destination is an existing directory, it moves the source into it.
  • Quote filenames with spaces, for example mv "old name.txt" "new name.txt".
  • -- ends option parsing and protects a path beginning with -; variables must still be double-quoted.
  • Recursive operations also require checks of symbolic links, mount points, and the expected root. Do not assume sudo.

Safe exercise and acceptance

Run the complete lab above. Verify that the output path matches $TMPDIR/file-ops.*, the target belongs to the current user, and it is not a symbolic link. Retain pwd -P, find . -maxdepth 3 -print, and exit statuses. Confirm that only project/logs/backup.md was removed; do not practice recursive deletion.

References