展平目录但在新文件名中保留目录名称

Nat*_*.B. 13 find rename

如何按以下格式展平目录?

前: ./aaa/bbb/ccc.png

后: ./aaa-bbb-ccc.png

Dav*_*hen 10

虽然这里已经有很好的答案,但我发现这更直观,在bash

find aaa -type f -exec sh -c 'new=$(echo "{}" | tr "/" "-" | tr " " "_"); mv "{}" "$new"' \;
Run Code Online (Sandbox Code Playgroud)

aaa您现有的目录在哪里。它包含的文件将被移动到当前目录(只留下 aaa 中的空目录)。tr处理目录和空格的两个调用(没有转义斜杠的逻辑 - 读者练习)。

我认为这更直观且相对容易调整。即find如果说我只想找到 .png 文件,我可以更改参数。我可以更改tr呼叫,或根据需要添加更多呼叫。如果我想直观地检查它是否会做正确的事情,我可以添加echo之前mv(然后echo仅在事情看起来正确时重复而不额外添加:

find aaa -name \*.png -exec sh -c 'new=$(echo "{}" | tr "/" "-" | tr " " "_"); echo mv "{}" "$new"' \;
Run Code Online (Sandbox Code Playgroud)

另请注意,我使用的是find aaa... 而不是find .... 或find aaa/... 因为后两者会在最终文件名中留下有趣的工件。


Gil*_*il' 7

警告:我直接在浏览器中输入了大部分命令。警告讲师。

使用 zsh 和zmv

zmv -o -i -Qn '(**/)(*)(D)' '${1//\//-}$2'
Run Code Online (Sandbox Code Playgroud)

说明:该模式**/*递归地匹配当前目录子目录中的所有文件(它不匹配当前目录中的文件,但这些不需要重命名)。前两对括号是可以在替换文本中称为$1和 的组$2。最后一对括号添加了D glob 限定符,以便不会省略点文件。-o -i表示将-i选项传递给,mv以便在现有文件将被覆盖时提示您。


仅使用 POSIX 工具:

find . -depth -exec sh -c '
    for source; do
      case $source in ./*/*)
        target="$(printf %sz "${source#./}" | tr / -)";
        mv -i -- "$source" "${target%z}";;
      esac
    done
' _ {} +
Run Code Online (Sandbox Code Playgroud)

说明:case语句省略了当前目录和当前目录的顶级子目录。target包含源文件名 ( $0),./去掉前导,所有斜线都替换为破折号,加上最后的z. 最后z是在文件名以换行符结尾的情况下:否则命令替换将删除它。

如果你find不支持-exec … +(OpenBSD,我在看着你):

find . -depth -exec sh -c '
    case $0 in ./*/*)
      target="$(printf %sz "${0#./}" | tr / -)";
      mv -i -- "$0" "${target%z}";;
    esac
' {} \;
Run Code Online (Sandbox Code Playgroud)

使用 bash(或 ksh93),您不需要调用外部命令来用破折号替换斜杠,您可以使用带有字符串替换构造的 ksh93 参数扩展${VAR//STRING/REPLACEMENT}

find . -depth -exec bash -c '
    for source; do
      case $source in ./*/*)
        source=${source#./}
        target="${source//\//-}";
        mv -i -- "$source" "$target";;
      esac
    done
' _ {} +
Run Code Online (Sandbox Code Playgroud)