问题
It would be best if I could just use the rename command. But I think we have to use two regex.
The sed command that is working is
% echo MyExPression | sed --expression 's/\([A-Z]\)/-\L\1/g' --expression 's/^-//'
my-ex-pression
% echo myExPression | sed --expression 's/\([A-Z]\)/-\L\1/g' --expression 's/^-//'
my-ex-pression
I figured out that we can use
for file in ./* ; do mv "$file" "$(echo $file|sed -e 's/\([A-Z]\)/-\L\1/g' -e 's/^.\/-//')" ; done
But this command has multiple problems.
- It operates on both files and directories. I want to rename directories only
- It does not loop recursively.
- If kebab case filename is already there then it says
mv: cannot move './first-folder-to-rename' to a subdirectory of itself, './first-folder-to-rename/first-folder-to-rename'
So, what might be the solution here?
Update 1
Here is a sample directory structure
% tree
.
├── EmptyFile.txt
├── FirstDirectoryName
│ ├── FourthDirectoryName
│ ├── secondDirectoryName
│ └── thirdDirectoryName
├── FourthDirectoryName
├── secondDirectoryName
└── thirdDirectoryName
Expected Output
% tree
.
├── EmptyFile.txt
├── first-directory-name
│ ├── fourth-directory-name
│ ├── second-directory-name
│ └── third-directory-name
├── fourth-directory-name
├── second-directory-name
└── third-directory-name
回答1:
zsh:
autoload -Uz zmv
zmv -n -Q '**/|*[[:upper:]]*(/od)' \
'${(M)f##*/}${(L)${${f##*/}//(#b)([[:upper:]])/-$match[1]}#-}'
remove -n if output is correct.
回答2:
find + shell + sed + tr:
find . -depth -type d -name '*[[:upper:]]*' -exec sh -c '
for i do
parent=${i%/*}
[ "$parent" = "$i" ] && parent="" || parent="$parent/"
newname=$(sed '\''s/\(.\)\([[:upper:]]\)/\1-\2/g'\'' <<X | tr "[:upper:]" "[:lower:]"
${i##*/}
X
)
echo mv -- "$i" "$parent$newname"
done' _ {} +
回答3:
Using bash and GNU sed:
$ cat rendirs
#!/bin/bash
# function for renaming directories recursively
rendirrec () {
local from to
for from in *; do
[[ -d $from && ! -h $from ]] || continue
to=$(sed -E 's/([^A-Z])([A-Z])/\1-\2/g; s/.*/\L&/' <<< "$from")
cd "$from" && { rendirrec; cd ..; } || exit
[[ $to = "$from" ]] && continue
if [[ -e $to ]]; then
printf "'%s' already exists. Skipping..\n" "$to" >&2
continue;
fi
mv "$from" "$to" || exit
done
}
[[ -z $1 ]] && { echo "Missing argument" >&2; exit 1; }
cd "$1" && rendirrec
Run as$ ./rendirs top_of_the_directory_tree_to_be_renamed
来源:https://stackoverflow.com/questions/62845379/rename-directories-recursively-from-pascal-or-camel-case-to-kebab-case