Created
July 1, 2025 13:46
-
-
Save imCorfitz/40675c95e38fd7c5323793d14f40e542 to your computer and use it in GitHub Desktop.
Convert files and directories to kebab-case
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 | |
# Script to convert all directory and file names to kebab-case | |
# Usage: ./convert-to-kebab-case.sh | |
set -e | |
# Function to convert string to kebab-case | |
to_kebab_case() { | |
local input="$1" | |
# Remove file extension temporarily | |
local extension="" | |
local basename="$input" | |
if [[ "$input" == *.* ]]; then | |
extension=".${input##*.}" | |
basename="${input%.*}" | |
fi | |
# Convert to kebab-case: | |
# 1. Replace camelCase with kebab-case (insert hyphen before uppercase letters) | |
# 2. Replace underscores and spaces with hyphens | |
# 3. Convert to lowercase | |
# 4. Remove multiple consecutive hyphens | |
local kebab=$(echo "$basename" | \ | |
sed 's/\([a-z0-9]\)\([A-Z]\)/\1-\2/g' | \ | |
sed 's/[_[:space:]]\+/-/g' | \ | |
tr '[:upper:]' '[:lower:]' | \ | |
sed 's/-\+/-/g' | \ | |
sed 's/^-\|-$//g') | |
echo "${kebab}${extension}" | |
} | |
# Function to rename files and directories recursively | |
rename_items() { | |
local current_dir="$1" | |
# Process files first, then directories (to avoid path issues) | |
find "$current_dir" -depth -type f -not -path "*/node_modules/*" -not -path "*/.git/*" | while read -r filepath; do | |
local dir=$(dirname "$filepath") | |
local filename=$(basename "$filepath") | |
local new_filename=$(to_kebab_case "$filename") | |
if [[ "$filename" != "$new_filename" ]]; then | |
local new_filepath="$dir/$new_filename" | |
# Check if it's a case-only change on case-insensitive filesystem | |
if [[ "$(echo "$filename" | tr '[:upper:]' '[:lower:]')" == "$(echo "$new_filename" | tr '[:upper:]' '[:lower:]')" ]]; then | |
# Two-step rename for case-only changes | |
local temp_filepath="$dir/${filename}.tmp.$$" | |
echo "Renaming file (case-only): $filepath -> $new_filepath" | |
mv "$filepath" "$temp_filepath" | |
mv "$temp_filepath" "$new_filepath" | |
elif [[ ! -e "$new_filepath" ]]; then | |
echo "Renaming file: $filepath -> $new_filepath" | |
mv "$filepath" "$new_filepath" | |
else | |
echo "Warning: Target file already exists, skipping: $new_filepath" | |
fi | |
fi | |
done | |
# Process directories from deepest to shallowest | |
find "$current_dir" -depth -type d -not -path "*/node_modules/*" -not -path "*/.git/*" | while read -r dirpath; do | |
local parent_dir=$(dirname "$dirpath") | |
local dirname=$(basename "$dirpath") | |
local new_dirname=$(to_kebab_case "$dirname") | |
if [[ "$dirname" != "$new_dirname" ]]; then | |
local new_dirpath="$parent_dir/$new_dirname" | |
# Check if it's a case-only change on case-insensitive filesystem | |
if [[ "$(echo "$dirname" | tr '[:upper:]' '[:lower:]')" == "$(echo "$new_dirname" | tr '[:upper:]' '[:lower:]')" ]]; then | |
# Two-step rename for case-only changes | |
local temp_dirpath="$parent_dir/${dirname}.tmp.$$" | |
echo "Renaming directory (case-only): $dirpath -> $new_dirpath" | |
mv "$dirpath" "$temp_dirpath" | |
mv "$temp_dirpath" "$new_dirpath" | |
elif [[ ! -e "$new_dirpath" ]]; then | |
echo "Renaming directory: $dirpath -> $new_dirpath" | |
mv "$dirpath" "$new_dirpath" | |
else | |
echo "Warning: Target directory already exists, skipping: $new_dirpath" | |
fi | |
fi | |
done | |
} | |
# Confirm before proceeding | |
echo "This script will rename all files and directories to kebab-case." | |
echo "It will skip node_modules and .git directories." | |
echo "Make sure you have a backup of your project before proceeding!" | |
echo "" | |
read -p "Do you want to continue? (y/N): " -n 1 -r | |
echo "" | |
if [[ ! $REPLY =~ ^[Yy]$ ]]; then | |
echo "Operation cancelled." | |
exit 0 | |
fi | |
# Get the directory to process (default to current directory) | |
target_dir="${1:-.}" | |
if [[ ! -d "$target_dir" ]]; then | |
echo "Error: Directory '$target_dir' does not exist." | |
exit 1 | |
fi | |
echo "Processing directory: $target_dir" | |
echo "" | |
# Start the renaming process | |
rename_items "$target_dir" | |
echo "" | |
echo "Renaming complete!" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment