Add exclude option to find_duplicate_pictures.sh

This commit is contained in:
2026-08-28 17:55:20 +03:00
parent 7ad8ca8e75
commit 81c2a81c7d
2 changed files with 58 additions and 4 deletions
+13
View File
@@ -32,6 +32,9 @@ three independent checks:
# Scan specific roots
./find_duplicate_pictures.sh /home/user/Pictures /mnt/backup
# Scan a collection while skipping cache and export directories
./find_duplicate_pictures.sh --exclude ~/Pictures/Cache --exclude ~/Pictures/Exports ~/Pictures
# Scan the whole filesystem (default when no arguments given)
./find_duplicate_pictures.sh
@@ -50,6 +53,16 @@ chmod +x find_duplicate_pictures.sh
| `FOLLOW_LINKS` | `0` (off) | Set to `1` to follow symlinks while scanning |
| `REPORT` | *(none)* | Path to a file where the full report is also saved |
### Directory exclusions
Use `-x DIR` or `--exclude DIR` to skip a directory and all of its contents.
The option may be repeated and accepts paths containing spaces. Relative paths
are supported for both scan roots and exclusions.
```bash
./find_duplicate_pictures.sh -x ~/Pictures/Cache -x ~/Pictures/Exports ~/Pictures
```
### Examples
```bash
+45 -4
View File
@@ -14,18 +14,22 @@
# pre-filter before hashing.
#
# Usage:
# ./find_duplicate_pictures.sh [DIR ...]
# ./find_duplicate_pictures.sh [--exclude DIR ...] [DIR ...]
# ./find_duplicate_pictures.sh # defaults to "/" (whole system)
#
# Examples:
# ./find_duplicate_pictures.sh / /mnt/c /mnt/d
# ./find_duplicate_pictures.sh ~/Pictures
# ./find_duplicate_pictures.sh --exclude ~/Pictures/Cache ~/Pictures
#
# Options (environment variables):
# HASH_CMD=sha256sum # override hash tool (sha256sum, shasum -a 256, md5sum)
# FOLLOW_LINKS=1 # follow symlinks while scanning (default: off)
# REPORT=report.txt # also write the report to a file
#
# Options:
# -x, --exclude DIR # skip DIR and everything below it (repeatable)
#
set -u
@@ -82,12 +86,46 @@ build_ext_expr() {
# Arguments / scan roots
# ---------------------------------------------------------------------------
if [ "$#" -gt 0 ]; then
ROOTS=("$@")
else
ROOTS=()
EXCLUDE_DIRS=()
while [ "$#" -gt 0 ]; do
case "$1" in
-x|--exclude)
if [ "$#" -lt 2 ]; then
echo "ERROR: $1 requires a directory path." >&2
exit 1
fi
EXCLUDE_DIRS+=("$2")
shift 2
;;
--)
shift
ROOTS+=("$@")
break
;;
*)
ROOTS+=("$1")
shift
;;
esac
done
if [ "${#ROOTS[@]}" -eq 0 ]; then
ROOTS=("/")
fi
# Use absolute paths because find emits paths relative to the supplied root.
for index in "${!ROOTS[@]}"; do
if [ -d "${ROOTS[$index]}" ]; then
ROOTS[$index]=$(cd "${ROOTS[$index]}" && pwd -P)
fi
done
for index in "${!EXCLUDE_DIRS[@]}"; do
if [ -d "${EXCLUDE_DIRS[$index]}" ]; then
EXCLUDE_DIRS[$index]=$(cd "${EXCLUDE_DIRS[$index]}" && pwd -P)
fi
done
FIND_LINK_FLAG=()
if [ "${FOLLOW_LINKS:-0}" = "1" ]; then
FIND_LINK_FLAG=(-L)
@@ -98,6 +136,9 @@ PRUNE_EXPR=()
for d in $PRUNE_DIRS; do
PRUNE_EXPR+=( -path "$d" -prune -o )
done
for d in "${EXCLUDE_DIRS[@]}"; do
PRUNE_EXPR+=( -path "$d" -prune -o )
done
# Extension expression
mapfile -t EXT_EXPR < <(build_ext_expr)