【问题标题】:osx terminal: renaming files by hierarchyosx终端:按层次重命名文件
【发布时间】:2017-06-29 17:25:37
【问题描述】:

在 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”?

非常感谢您!

【问题讨论】:

    标签: bash macos terminal rename flatten


    【解决方案1】:

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

    (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

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

    find /path -type d -empty -delete
    

    【讨论】:

    • 谢谢!将尽快尝试。 – 您能告诉我(或指出)newname=${1:2} 和 newname//\/- 各自的作用吗?
    • 我添加了更多解释,并修复了一个重要的错字。替换应该是newname=${newname//\//-},而不是我编辑之前的newname=${newname//\/-}
    • 谢谢,杰诺斯!实际上,我希望目录名附加在 /after/ 原始文件名之后。如何告诉 mv 附加参数而不是附加参数? (另外,我怎么能完全删除 / 字符而不是用 - 替换它?我不能用“无字符”替换,对吧?)
    【解决方案2】:

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

    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等)中。

    【讨论】:

      猜你喜欢
      • 2016-01-12
      • 1970-01-01
      • 2021-07-23
      • 1970-01-01
      • 1970-01-01
      • 2017-10-28
      • 2018-07-27
      • 2013-05-31
      • 1970-01-01
      相关资源
      最近更新 更多