find deleted files
Sometimes you want to compare an archive backup drive and a target folder and see what items got deleted in that folder. Useful if you have a flaky backup system like dropbox.
#!/usr/bin/env bash
# find_deleted.sh — list non-image files that exist in SOURCE but not in TARGET
# usage: ./find_deleted.sh [--rsync-check] SOURCE_DIR TARGET_DIR
set -euo pipefail
usage() {
echo "Usage: $0 [--rsync-check] SOURCE_DIR TARGET_DIR" >&2
exit 1
}
RSYNC_CHECK=0
if [ "${1:-}" = "--rsync-check" ]; then
RSYNC_CHECK=1
shift
fi
[ $# -eq 2 ] || usage
SRC="${1%/}"
DST="${2%/}"
[ -d "$SRC" ] || { echo "Source not found: $SRC" >&2; exit 2; }
[ -d "$DST" ] || { echo "Target not found: $DST" >&2; exit 3; }
# Returns 0 if the path looks like an image, 1 otherwise.
is_image_path() {
# lower-case path (Bash-only ${var,,})
local p="${1,,}"
case "$p" in
*.jpg|*.jpeg|*.png|*.gif|*.bmp|*.tif|*.tiff|*.webp|*.heic|*.heif|*.svg|\
*.cr2|*.nef|*.arw|*.dng|*.rw2|*.orf|*.raf)
return 0 ;;
*) return 1 ;;
esac
}
missing_count=0
image_skipped=0
scanned=0
echo "Scanning (non-images only). Source: $SRC Target: $DST" >&2
# Use a pipeline instead of process substitution for /bin/sh safety (still Bash script).
find "$SRC" -type f -print0 | while IFS= read -r -d '' f; do
scanned=$((scanned + 1))
rel="${f#"$SRC"/}"
if is_image_path "$rel"; then
image_skipped=$((image_skipped + 1))
continue
fi
tgt="$DST/$rel"
if [ ! -e "$tgt" ]; then
echo "$rel"
missing_count=$((missing_count + 1))
fi
# Lightweight progress feedback every 500 files
if [ $((scanned % 500)) -eq 0 ]; then
echo "…scanned $scanned (missing so far: $missing_count, images skipped: $image_skipped)" >&2
fi
done
echo "Done. Scanned: $scanned; Missing (non-images): $missing_count; Images skipped: $image_skipped" >&2
# Optional cross-check using rsync (dry-run, excludes images).
if [ "$RSYNC_CHECK" -eq 1 ]; then
echo >&2
echo "rsync dry-run cross-check (non-images). Differences rsync would copy from SRC->DST:" >&2
rsync -ani \
--exclude='*.jpg' --exclude='*.jpeg' --exclude='*.png' --exclude='*.gif' \
--exclude='*.bmp' --exclude='*.tif' --exclude='*.tiff' --exclude='*.webp' \
--exclude='*.heic' --exclude='*.heif' --exclude='*.svg' --exclude='*.cr2' \
--exclude='*.nef' --exclude='*.arw' --exclude='*.dng' --exclude='*.rw2' \
--exclude='*.orf' --exclude='*.raf' \
--delete --ignore-existing \
"$SRC/" "$DST/" | sed 's/^/> /' >&2
echo "Note: rsync output is informational only (dry run). No changes made." >&2
fi