osx终端:按层次结构重命名文件

时间:2017-02-11 10:57:59

标签: bash macos terminal rename flatten

在OSX终端中,我尝试压缩文件夹层次结构,但由于里面的文件名称相同,我想用以前的文件夹名称扩展文件名:

我想从这里开始:

/dirA1/dirB1/file1.ext
/dirA1/dirB2/file1.ext
...
/dirA2/dirB1/file1.ext
...

/file1-dirA1-dirB1.ext
/file1-dirA1-dirB2.ext
...
/file1-dirA2-dirB1.ext
...

我尝试将重命名(Batch renaming files in OSX terminal)与展平(https://unix.stackexchange.com/questions/52814)结合起来,但没有运气......

我会从“发现”开始吗?但是如何将目录名称传递给“mv”?

非常感谢你!

2 个答案:

答案 0 :(得分:0)

一种安全但不是很快的方法是将Bfind一起使用,将每个文件传递给执行替换的shell命令,如下所示:

-exec

(cd /path; find . -type f -exec sh -c 'newname=${1:2}; filename=${newname##*/}; dirname=${newname%/*}; newname=$filename-${dirname//\//-}; echo mv "$1" "$newname"' -- {} \;) 而不是cd /path的原因是我们可以使用该基本目录中的相对路径,这样可以更轻松地创建拼合文件名。

对元素的更多解释:

  • find /path执行-exec sh -c '...' -- {},运行sh中指定的命令。 -c '...'{}找到的路径。 find语法是将参数作为位置参数传递给脚本,可通过-- ...$1访问,等等。
  • $2获取newname=${1:2},第一个位置参数,并从中提取子字符串,跳过前两个字符。我这样做是因为$1的输出将包含以find .开头的路径,我们希望在用./替换/之前将其删除。
  • -提取路径的文件名部分,删除从开头到最后filename=${newname##*/}的所有内容
  • /提取路径的目录名称部分,删除最后一个dirname=${newname%/*}及其后的所有内容
  • /将所有${dirname//\//-}替换为/。如果您要删除-而不是替换,则可以编写/

这种技术是安全的,因为它可以与文件名中的任何特殊字符一起使用。它很慢,因为它为每个文件运行${dirname//\//}

在此步骤之后,原始文件的空目录将保留,您可能想要删除它们:

sh

答案 1 :(得分:0)

通过将sh输出提供给find … -print0循环,您可以安全地处理此问题而不对每个文件执行while read,例如:

while IFS= read -r -d '' old; do            # read filenames into $old
                                            # -d ''  : read until \0
                                            # -r     : no backslash escapes
                                            # IFS=   : no trimming whitespace
    if [[ $old =~ (.*)/(.*)\.(.*) ]]; then  # regex with capture groups:
       #           1    2     3
       set -- "${BASH_REMATCH[@]}"
       mv "$old" "${2}-${1//\/}.${3}"
    fi
done < <(find . -type f -print 0)

上面set -- "${BASH_REMATCH[@]}"的目的只是将包含正则表达式匹配组的数组成员移动到位置参数($1$2等)中易读性。