Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 将目录从pascal或camel case递归重命名为kebab case_Bash_Zsh - Fatal编程技术网

Bash 将目录从pascal或camel case递归重命名为kebab case

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:无法将“./要重命名

如果我可以使用rename命令,那将是最好的。但我认为我们必须使用两个正则表达式

问题是

我相信我们可以使用

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' _ {} +