Skip to content

Instantly share code, notes, and snippets.

@john-hamnavoe
Last active March 15, 2025 22:49
Show Gist options
  • Select an option

  • Save john-hamnavoe/58ea077ca59d76d0d01a99a4fde2cbf3 to your computer and use it in GitHub Desktop.

Select an option

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
#!/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