Bash 将目录从pascal或camel case递归重命名为kebab case
如果我可以使用rename命令,那将是最好的。但我认为我们必须使用两个正则表达式 问题是 我相信我们可以使用Bash 将目录从pascal或camel case递归重命名为kebab case,bash,zsh,Bash,Zsh,如果我可以使用rename命令,那将是最好的。但我认为我们必须使用两个正则表达式 问题是 我相信我们可以使用 for file in ./* ; do mv "$file" "$(echo $file|sed -e 's/\([A-Z]\)/-\L\1/g' -e 's/^.\/-//')" ; done 但是这个命令有多个问题 它在文件和目录上运行。我只想重命名目录 它不会递归地循环。 如果烤肉串的文件名已经存在,那么它会说 mv:无法将“./要重命名
for file in ./* ; do mv "$file" "$(echo $file|sed -e 's/\([A-Z]\)/-\L\1/g' -e 's/^.\/-//')" ; done
但是这个命令有多个问题
它在文件和目录上运行。我只想重命名目录
它不会递归地循环。
如果烤肉串的文件名已经存在,那么它会说
mv:无法将“./要重命名的第一个文件夹”移动到其自身的子目录“./要重命名的第一个文件夹/要重命名的第一个文件夹”
那么,这里的解决方案是什么
更新1
下面是一个示例目录结构
% tree
.
├── EmptyFile.txt
├── FirstDirectoryName
│ ├── FourthDirectoryName
│ ├── secondDirectoryName
│ └── thirdDirectoryName
├── FourthDirectoryName
├── secondDirectoryName
└── thirdDirectoryName
预期产量
% tree
.
├── EmptyFile.txt
├── first-directory-name
│ ├── fourth-directory-name
│ ├── second-directory-name
│ └── third-directory-name
├── fourth-directory-name
├── second-directory-name
└── third-directory-name
zsh:
如果输出正确,请删除-n。zsh:
如果输出正确,请删除-n。使用bash和GNU-sed:
$cat rendirs
作为
$./rendirs目录树的顶部将使用bash和GNU-sed重命名:
$cat rendirs
作为
$./rendirs目录树的顶部要重命名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' _ {} +
查找+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' _ {} +
请将示例文件名无描述、无图像、无链接以及该示例输入所需的文件名添加到问题中无注释。这可能有助于GNU sed:sed的/[A-Z]/-\L&/g;s/^-/'请将示例文件名无描述、无图像、无链接和您所需的文件名添加到您的问题中,无评论。这可能有助于GNU sed:sed的/[A-Z]/-\L&/g;s/^-/'调整全局限定符:。仅适用于普通文件的od;任何类型的od。检查man zshexpn节全局限定符以了解许多其他可能性。od排序是必需的,这样大多数嵌套的文件都会像使用find时的-depth一样首先被处理。@blueray$f是由zmv匹配的文件名。由于zsh可以嵌套参数扩展,因此可以应用一些修改。从最里面的*/开始删除父路径(如果有)。然后,一个全局替换和反向引用由b启用,在每个大写字母之前添加一个连字符。最外层的展开将结果小写,并删除单个前导连字符。一个改进是:${L${f*/}//b[:upper:]/$match[1]-$match[2]}。将添加一个带有M标志的单独的*/以匹配任何现有的父路径。[[:upper:]不会处理重复的大写字母。例如,IsIBad->is-ibad@blueray***是个坏主意。使用**/*[:upper:]*/,并将第二个参数更改为${1}${L${2//b[:upper:]/-$match[1]}-}.*/用于递归。将dirname和basename捕获为$1和$2。/是所需的唯一限定符,因为od已在中。很抱歉发布错误答案。请调整全局限定符:。od仅适用于普通文件;任何类型的od。检查man zshexpn节全局限定符以了解许多其他可能性。od排序是必需的,这样大多数嵌套的文件都会像使用find时的-depth一样首先被处理。@blueray$f是由zmv匹配的文件名。由于zsh可以嵌套参数扩展,因此可以应用一些修改。从最里面的*/开始删除父路径(如果有)。然后,一个全局替换和反向引用由b启用,在每个大写字母之前添加一个连字符。最外层的展开将结果小写,并删除单个前导连字符。一个改进是:${L${f*/}//b[:upper:]/$match[1]-$match[2]}。将添加一个带有M标志的单独的*/以匹配任何现有的父路径。[[:upper:]不会处理重复的大写字母。例如,IsIBad->is-ibad@blueray***是个坏主意。使用**/*[:upper:]*/,并将第二个参数更改为${1}${L${2//b[:upper:]/-$match[1]}-}.*/用于递归。将dirname和basename捕获为$1和$2。/是所需的唯一限定符,因为od已在中。很抱歉发布了错误的答案。@blueray现在似乎已经更正了。添加了bash标记。是的,我回滚了。@blueray bash标记再次被删除@blueray代码中存在逻辑错误。纠正now@blueray现在看来已经纠正了。添加了bash标记。是的,我回滚了。@blueray bash标记再次被删除@blueray代码中存在逻辑错误。已更正的nows/\.\[:upper:]\/\1-\2/g无法正确处理重复的大写字母。s/\.\[:upper:]\/\1-\2/g无法正确处理重复的大写字母。
#!/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
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' _ {} +