Skip to content

Instantly share code, notes, and snippets.

@gerbal
Created October 23, 2023 18:46
Show Gist options
  • Save gerbal/48652378ec21a5fbb5fc72659c510faa to your computer and use it in GitHub Desktop.
Save gerbal/48652378ec21a5fbb5fc72659c510faa to your computer and use it in GitHub Desktop.
bulk-rename.sh - simple bash script to rename a module or class accross a whole project
#!/bin/bash
# Bulk Rename Script
# This script helps to refactor code by renaming occurrences of a module name or file name across the project.
# It respects existing naming conventions, i.e., snake_case and PascalCase, during the renaming process.
#
# Usage: ./bulk-rename.sh <from> <to> [-v|--verbose] [-d|--ignore-dirs]
#
# Options:
# -v, --verbose Print detailed logs of the renaming process.
# -d, --ignore-dirs Skip renaming directories.
#
# Author: ChatGPT (OpenAI)
FROM=$1
TO=$2
VERBOSE=0
IGNORE_DIRS=0
# Check for flags
for arg in "$@"; do
if [ "$arg" == "-v" ] || [ "$arg" == "--verbose" ]; then
VERBOSE=1
elif [ "$arg" == "-d" ] || [ "$arg" == "--ignore-dirs" ]; then
IGNORE_DIRS=1
fi
done
echo $VERBOSE
echo $IGNORE_DIRS
# Check if the user provided at least two arguments
if [ "$#" -lt 2 ]; then
echo "Usage: $0 <from> <to> [-v|--verbose] [-d|--ignore-dirs]"
exit 1
fi
# Convert from PascalCase to snake_case
function pascal_to_snake() {
echo $1 | sed -r 's/([a-z0-9])([A-Z])/\1_\2/g' | tr 'A-Z' 'a-z'
}
# Convert from snake_case to PascalCase
function snake_to_pascal() {
echo $1 | tr 'A-Z' 'a-z' | sed -r 's/(^|_)([a-z])/\U\2/g'
}
# Convert FROM and TO to snake_case and PascalCase
FROM_SNAKE=$(pascal_to_snake $FROM)
TO_SNAKE=$(pascal_to_snake $TO)
FROM_PASCAL=$(snake_to_pascal $FROM)
TO_PASCAL=$(snake_to_pascal $TO)
# Prepare list of files to exclude
EXCLUDES=(".git")
if [ -f ".gitignore" ]; then
while IFS= read -r line; do
[ -z "$line" ] && continue
[ "${line:0:1}" == "#" ] && continue
EXCLUDES+=("$line")
done < ".gitignore"
fi
# Replace in files and rename files
find . -type f | while read -r file; do
for exclude in "${EXCLUDES[@]}"; do
if [[ $file == *$exclude* ]]; then
continue 2
fi
done
if [ $VERBOSE -eq 1 ]; then
echo "Replacing in file $file..."
fi
sed -i -e "s/$FROM/$TO/g" -e "s/$FROM_SNAKE/$TO_SNAKE/g" -e "s/$FROM_PASCAL/$TO_PASCAL/g" "$file"
NEW_NAME=$(echo $file | sed -e "s/$FROM/$TO/g" -e "s/$FROM_SNAKE/$TO_SNAKE/g" -e "s/$FROM_PASCAL/$TO_PASCAL/g")
if [ "$file" != "$NEW_NAME" ]; then
if [ $VERBOSE -eq 1 ]; then
echo "Renaming $file to $NEW_NAME..."
fi
mv "$file" "$NEW_NAME"
fi
done
# Rename directories
if [ $IGNORE_DIRS -eq 0 ]; then
find . -type d | sort -r | while read -r dir; do
for exclude in "${EXCLUDES[@]}"; do
if [[ $dir == *$exclude* ]]; then
continue 2
fi
done
NEW_NAME=$(echo $dir | sed -e "s/$FROM/$TO/g" -e "s/$FROM_SNAKE/$TO_SNAKE/g" -e "s/$FROM_PASCAL/$TO_PASCAL/g")
if [ "$dir" != "$NEW_NAME" ]; then
if [ $VERBOSE -eq 1 ]; then
echo "Renaming $dir to $NEW_NAME..."
fi
mv "$dir" "$NEW_NAME"
fi
done
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment