Created
February 17, 2026 15:26
-
-
Save ralph/6d1e535267a99cf1fe52b504e1f25853 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Example file structure: | |
| # . | |
| # ├── jpg | |
| # │ ├── 123.jpg | |
| # │ ├── 789.jpg | |
| # │ └── 890.jpg | |
| # └── raw | |
| # ├── 123.raw | |
| # ├── 456.raw | |
| # └── 789.raw | |
| # | |
| # ❯ ./compare_folders.sh raw jpg | |
| # Only in raw: | |
| # raw/456.raw | |
| # | |
| # Only in jpg: | |
| # jpg/890.jpg | |
| # | |
| # ======================================== | |
| # WARNING: Deletion is PERMANENT and | |
| # UNRECOVERABLE! Files will NOT go to Trash. | |
| # ======================================== | |
| # | |
| # Would you like to delete the unmatched files? | |
| # 1) Delete files in raw that are missing in jpg | |
| # 2) Delete files in jpg that are missing in raw | |
| # 3) Do nothing and exit | |
| # | |
| # Choose [1/2/3]: | |
| # | |
| if [ $# -lt 2 ]; then | |
| echo "Usage: $0 <folder1> <folder2>" | |
| exit 1 | |
| fi | |
| dir1="$1" | |
| dir2="$2" | |
| # Extract basenames without extensions | |
| names1=$(ls "$dir1" | sed 's/\.[^.]*$//' | sort) | |
| names2=$(ls "$dir2" | sed 's/\.[^.]*$//' | sort) | |
| only_in_1=$(comm -23 <(echo "$names1") <(echo "$names2")) | |
| only_in_2=$(comm -13 <(echo "$names1") <(echo "$names2")) | |
| if [ -n "$only_in_1" ]; then | |
| echo "Only in $dir1:" | |
| for name in $only_in_1; do | |
| ls "$dir1"/"$name".* 2>/dev/null | |
| done | |
| echo "" | |
| fi | |
| if [ -n "$only_in_2" ]; then | |
| echo "Only in $dir2:" | |
| for name in $only_in_2; do | |
| ls "$dir2"/"$name".* 2>/dev/null | |
| done | |
| echo "" | |
| fi | |
| if [ -z "$only_in_1" ] && [ -z "$only_in_2" ]; then | |
| echo "All file basenames match between the two folders." | |
| exit 0 | |
| fi | |
| # Offer to delete | |
| echo "========================================" | |
| echo "WARNING: Deletion is PERMANENT and" | |
| echo "UNRECOVERABLE! Files will NOT go to Trash." | |
| echo "========================================" | |
| echo "" | |
| echo "Would you like to delete the unmatched files?" | |
| echo " 1) Delete files in $dir1 that are missing in $dir2" | |
| echo " 2) Delete files in $dir2 that are missing in $dir1" | |
| echo " 3) Do nothing and exit" | |
| echo "" | |
| read -rp "Choose [1/2/3]: " choice | |
| case "$choice" in | |
| 1) | |
| if [ -z "$only_in_1" ]; then | |
| echo "No unmatched files in $dir1. Nothing to delete." | |
| exit 0 | |
| fi | |
| echo "" | |
| echo "The following files will be PERMANENTLY deleted:" | |
| for name in $only_in_1; do | |
| ls "$dir1"/"$name".* 2>/dev/null | |
| done | |
| echo "" | |
| read -rp "Are you sure? Type YES to confirm: " confirm | |
| if [ "$confirm" = "YES" ]; then | |
| for name in $only_in_1; do | |
| rm -v "$dir1"/"$name".* 2>/dev/null | |
| done | |
| echo "Done." | |
| else | |
| echo "Aborted." | |
| fi | |
| ;; | |
| 2) | |
| if [ -z "$only_in_2" ]; then | |
| echo "No unmatched files in $dir2. Nothing to delete." | |
| exit 0 | |
| fi | |
| echo "" | |
| echo "The following files will be PERMANENTLY deleted:" | |
| for name in $only_in_2; do | |
| ls "$dir2"/"$name".* 2>/dev/null | |
| done | |
| echo "" | |
| read -rp "Are you sure? Type YES to confirm: " confirm | |
| if [ "$confirm" = "YES" ]; then | |
| for name in $only_in_2; do | |
| rm -v "$dir2"/"$name".* 2>/dev/null | |
| done | |
| echo "Done." | |
| else | |
| echo "Aborted." | |
| fi | |
| ;; | |
| *) | |
| echo "No files deleted." | |
| ;; | |
| esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment