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

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

如何将目录展平为以下格式?

前:./aaa/bbb/ccc.png

后:./aaa-bbb-ccc.png

答案1

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

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

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

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

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

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

答案2

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

使用 zsh 和兹马夫:

zmv -o -i -Qn '(**/)(*)(D)' '${1//\//-}$2'

说明:该模式**/*递归地匹配当前目录的子目录中的所有文件(它不匹配当前目录中的文件,但这些文件不需要重命名)。前两对括号是可以在替换文本中引用为$1和的组。$2最后一对括号添加D 全局限定符这样点文件就不会被遗漏。-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
' _ {} +

说明:该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
' {} \;

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

答案3

find . -mindepth 2 -type f -name '*' |
  perl -l000ne 'print $_;  s/\//-/g; s/^\.-/.\// and print' |
    xargs -0n2 mv 

注意:这不适用于包含\n.
当然,这只会移动类型f文件...
唯一的名称冲突来自于预先存在于密码

使用这个基本子集进行测试

rm -fr junk
rm -f  junk*hello*

mkdir -p  junk/junkier/junkiest
touch    'hello    hello'
touch    'junk/hello    hello'
touch    'junk/junkier/hello    hello'
touch    'junk/junkier/junkiest/hello    hello'

导致

./hello    hello
./junk-hello    hello
./junk-junkier-hello    hello
./junk-junkier-junkiest-hello    hello

答案4

只需通过管道将文件名+路径传递给tr命令即可。tr <replace> <with>

for FILE in `find aaa -name "*.png"`
do
  NEWFILE=`echo $FILE | tr '/' '-'`
  cp -v $FILE $NEWFILE
done

相关内容