Last active
March 15, 2025 22:49
-
-
Save john-hamnavoe/58ea077ca59d76d0d01a99a4fde2cbf3 to your computer and use it in GitHub Desktop.
ZSH script to identify files and folders starting/ending with space and having colon or backslash valid on Mac but problem on OneDrive
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 | |
| # Ensure a folder name is provided | |
| if [[ -z "$1" ]]; then | |
| echo "Usage: $0 <directory> [--rename]" | |
| echo " --rename: Replace problematic characters in filenames" | |
| exit 1 | |
| fi | |
| target_dir="$1" | |
| rename_mode=false | |
| # Check for rename flag | |
| if [[ "$2" == "--rename" ]]; then | |
| rename_mode=true | |
| echo "Rename mode enabled - will fix problematic filenames" | |
| fi | |
| # Ensure the provided path is a valid directory | |
| if [[ ! -d "$target_dir" ]]; then | |
| echo "Error: '$target_dir' is not a valid directory" | |
| exit 1 | |
| fi | |
| echo "Searching in directory: $target_dir" | |
| # Find files and directories inside the given folder | |
| find "$target_dir" -depth -print0 | while IFS= read -r -d '' path; do | |
| name="${path##*/}" # Extracts the filename or directory name safely | |
| # Skip .DS_Store files | |
| if [[ "$name" == ".DS_Store" ]]; then | |
| continue | |
| fi | |
| parent_dir="${path%/*}" # Get parent directory path | |
| # Check if it's a directory with a period in the name | |
| is_dir_with_period=false | |
| if [[ -d "$path" && "$name" =~ \. ]]; then | |
| is_dir_with_period=true | |
| fi | |
| # Check for all problematic patterns | |
| has_issue=false | |
| fixes_applied="" | |
| # Create a working copy of the name that we'll modify | |
| new_name="$name" | |
| # Check for leading period | |
| if [[ "$new_name" =~ ^\. && "$new_name" != "." && "$new_name" != ".." ]]; then | |
| has_issue=true | |
| # Remove leading period | |
| new_name="${new_name#.}" | |
| fixes_applied+="* Removed leading period\n" | |
| fi | |
| # Check for trailing period - replace with _fs | |
| if [[ "$new_name" =~ \.$ ]]; then | |
| has_issue=true | |
| # Replace trailing period with _fs | |
| new_name="${new_name%.}_fs" | |
| fixes_applied+="* Replaced trailing period with _fs\n" | |
| fi | |
| # Check for space before extension | |
| if [[ "$name" =~ ([[:space:]]+)(\.[^/]*)$ ]]; then | |
| has_issue=true | |
| # Capture the extension part | |
| extension="${BASH_REMATCH[2]}" | |
| # Remove the space before extension | |
| new_name="${new_name%${BASH_REMATCH[1]}${extension}}${extension}" | |
| fixes_applied+="* Removed space before extension\n" | |
| fi | |
| # Check for leading spaces | |
| if [[ "$new_name" =~ ^[[:space:]]+ ]]; then | |
| has_issue=true | |
| # Remove leading spaces | |
| new_name="${new_name#"${BASH_REMATCH[0]}"}" | |
| fixes_applied+="* Removed leading spaces\n" | |
| fi | |
| # Check for trailing spaces | |
| if [[ "$new_name" =~ [[:space:]]+$ ]]; then | |
| has_issue=true | |
| # Remove trailing spaces | |
| new_name="${new_name%"${BASH_REMATCH[0]}"}" | |
| fixes_applied+="* Removed trailing spaces\n" | |
| fi | |
| # Replace colons with underscores | |
| if [[ "$new_name" =~ : ]]; then | |
| has_issue=true | |
| new_name="${new_name//:/_}" | |
| fixes_applied+="* Replaced colons with underscores\n" | |
| fi | |
| # Replace backslashes with underscores | |
| if [[ "$new_name" =~ \\ ]]; then | |
| has_issue=true | |
| new_name="${new_name//\\/_}" | |
| fixes_applied+="* Replaced backslashes with underscores\n" | |
| fi | |
| # Replace question marks with underscores | |
| if [[ "$new_name" =~ \? ]]; then | |
| has_issue=true | |
| new_name="${new_name//\?/_}" | |
| fixes_applied+="* Replaced question marks with underscores\n" | |
| fi | |
| # For directories with periods, replace periods with underscores | |
| if [[ "$is_dir_with_period" == true ]]; then | |
| has_issue=true | |
| new_name="${new_name//./_}" | |
| fixes_applied+="* Replaced periods in directory name with underscores\n" | |
| fi | |
| # Handle case where name becomes empty after removing problematic characters | |
| if [[ -z "$new_name" ]]; then | |
| new_name="unnamed" | |
| fixes_applied+="* Created placeholder name 'unnamed' for empty filename\n" | |
| fi | |
| # If we found issues or it's a directory with period | |
| if [[ "$has_issue" == true || "$is_dir_with_period" == true ]]; then | |
| # Determine if it's a file or directory | |
| if [[ -d "$path" ]]; then | |
| item_type="DIRECTORY" | |
| else | |
| item_type="FILE" | |
| fi | |
| echo "Flagged $item_type: $path" | |
| # If rename mode is enabled and we have a different name | |
| if [[ "$rename_mode" == true && "$name" != "$new_name" ]]; then | |
| new_path="$parent_dir/$new_name" | |
| echo " - Renaming:" | |
| echo " From: $name" | |
| echo " To: $new_name" | |
| echo -e " - Fixes applied:\n$(echo -e "$fixes_applied" | sed 's/^/ /')" | |
| # Perform the rename | |
| mv -i "$path" "$new_path" | |
| if [[ $? -eq 0 ]]; then | |
| echo " ✓ Renamed successfully" | |
| else | |
| echo " ✗ Rename failed" | |
| fi | |
| elif [[ "$rename_mode" == false ]]; then | |
| echo " - Issues found:" | |
| if [[ "$name" =~ ^\. && "$name" != "." && "$name" != ".." ]]; then echo " * Starts with period"; fi | |
| if [[ "$name" =~ \.$ ]]; then echo " * Ends with period"; fi | |
| if [[ "$name" =~ ^[[:space:]] ]]; then echo " * Starts with space"; fi | |
| if [[ "$name" =~ : ]]; then echo " * Contains colon"; fi | |
| if [[ "$name" =~ [[:space:]]$ ]]; then echo " * Ends with space"; fi | |
| if [[ "$name" =~ \\ ]]; then echo " * Contains backslash"; fi | |
| if [[ "$name" =~ \? ]]; then echo " * Contains question mark"; fi | |
| if [[ "$name" =~ [[:space:]]\.[^/]*$ ]]; then echo " * Has space before file extension"; fi | |
| if [[ "$is_dir_with_period" == true ]]; then echo " * Directory with period in name"; fi | |
| echo " - Suggested new name: $new_name" | |
| fi | |
| fi | |
| done | |
| echo "Search complete." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment