Rename directories recursively from pascal or camel case to kebab case

邮差的信 提交于 2020-07-22 05:11:09

问题


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.

  1. It operates on both files and directories. I want to rename directories only
  2. It does not loop recursively.
  3. 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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!