【问题标题】:Recursively remove pattern from filenames without changing paths从文件名中递归删除模式而不更改路径
【发布时间】:2018-04-30 02:58:28
【问题描述】:

我在目录树中有数千个文件,文件名如下:

/Folder 0001 - 0500/0001 - Portrait - House.jpg
/Folder 2500 - 3000/2505 - Landscape - Mountain.jpg

使用 linux 命令行我想删除文件名中第一个单词之前的所有内容,例如“0001 -”和“2500 -”。新文件名如下所示:

/Folder 0001 - 0500/Portrait - House.jpg
/Folder 2500 - 3000/Landscape - Mountain.jpg

我修改了一个可行的脚本:

find . -type f -name "*-*" -exec bash -c 'f="$1"; g="${f/[[:digit:]]/ -/ /}"; echo mv -- "$f" "$g"' _ '{}' \;

这里的问题是它会删除部分路径而不是文件名,因此实际输出会生成如下文件名:

/Folder  -/ /001 - 0500/0001 - Portrait - House.jpg
/Folder  -/ /500 - 3000/2505 - Landscape - Mountain.jpg

如何修改此脚本以使用我描述的模式重命名文件?

【问题讨论】:

  • 它是如何屠宰路径的,你能举一个你得到的输出的例子吗?
  • @123,它将从路径中删除数字,仅此而已。
  • 正确。它从路径中删除数字而不是文件名。

标签: linux bash


【解决方案1】:
find . -mindepth 2 -type f -name "*-*" -exec bash -c '
  shopt -s extglob
  for arg do
    dir=${arg%/*}
    basename_old=${arg##*/}
    basename_new=${basename_old##+([[:digit:]]) - }
    [[ "$basename_new" = "$basename_old" ]] && continue   # skip when no rename needed
    printf "%q " mv -- "$dir/$basename_old" "$dir/$basename_new"
    printf "\n"
  done
' _ {} +

你可以在https://ideone.com/YJNL9c看到这段代码运行


  • 使用parameter expansions 将目录名从文件名中分离出来,可以单独操作这些文件名。
    • ${arg%/*}arg 中的变量中删除最后一个 / 之后的所有内容 - 从而删除文件名,离开目录,当路径 具有 至少一个目录段时(提供此保证是-mindepth 2 的原因)。
    • ${arg##*/} 从开头删除与 */ 的最长匹配 - 从而删除目录,保留基本文件名。
  • 通过启用the extglob shell option,我们在 fnmatch/glob 样式表达式中获得了类似正则表达式的功能,包括匹配一个或多个单个数字的能力;这就是为什么+([[:digit:]]) - 计算结果为“一位或多位数字,后跟-”。
  • 通过在生成 shell 命令时使用 printf '%q ' 而不是 echo,即使不控制文件名,我们也可以生成安全引用的输出。
  • 通过使用-exec ... {} +,我们将多个参数传递给每个bash 实例,而不是为找到的每个文件调用单独的解释器。使用for arg do,我们遍历所有这些参数。

【讨论】:

  • 这是一个很好的答案!我喜欢你为什么使用你所做的解释,这真的帮助我理解了这段代码实际上在做什么。谢谢!
猜你喜欢
  • 2020-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多