如何安全地将基于 REGEX 的文件移动和重命名到正确命名的目录中

如何安全地将基于 REGEX 的文件移动和重命名到正确命名的目录中

在一个大驱动器中,我有数百个文件,每个文件的名称不同,但带有一些正则表达式。每个附加随机数字,有时附加字符。

例如,有 30 个文件以单词“television”的变体命名,另外 50 个文件以“lightbulb”的变体命名。

问题是,由于多年前我在实现生成名称的脚本时采用了糟糕的编码实践,所以它非常不一致;所以我们可能会得到:

  • 电视139443.png
  • 电视244904.png
  • televisio097798.png
  • elevisio984882.png
  • _televisi90890890.png
  • TV-911181.png

你明白了。该模式适用于所有文件“类别”——“电视”、“灯泡”、“汽车”等。幸运的是,每个文件名中至少有 5 个一致的字符,这些字符在其他类别中不会重复(十几只猫) )。

我想要实现的是递归地遍历混合文件夹,使用正确的完整标题+附加创建日期重命名每个文件,并将它们移到各自的文件夹中。

有点像:

   case : regex("levis"):
rename to Television-($creation_date).($extension)
mv to ~/Categories/Television/
break;
    case : regex("ghtbu"):
rename to Lightbulb-($creation_date).($extension)
mv to ~/Categories/Lightbulbs/
break;

显然这不是正确的代码;这只是为了说明这个想法。我对日常 bash/zsh 任务相当满意,但不够流畅!

我还需要优雅地处理没有正则表达式匹配的情况。

答案1

使用zsh,您可以根据其近似匹配功能使用不同的方法:

autoload zmv # best in ~/.zshrc
zmodload zsh/stat

dest=~/Categories
categories=(television lightbulb motorcar etc)
mkdir -p -- $dest/${(C)^categories}

zmv -n '(**/)(*[^0-9])<->(.*)' \
       '$dest/${c::=${${(CM)categories:#(#a3)$2}:-unknown}}/$c-$(
          zstat -F %FT%T%z +mtime -- $f)$3'

${(M)categories:#(#a3)$2}数组中的查找($2数字之前的部分)categories最多允许三个错误(不同字符、转置、插入、删除)。

如果正常,请移除-n(空运行)。

对于你的方法,它可能是这样的:

autoload zmv # best in ~/.zshrc
zmodload zsh/stat

dest=~/Categories
typeset -A categories

categories=(
  levis Television
  ghtbu Lightbulb
  otorc Motocar
)

mkdir -p -- $dest/$^categories

for k (${(k)categories}) (
  zmv -n "(**/)*$k*(.*)" '$dest/$categories[$k]/$categories[$k]-$(
          zstat -F %FT%T%z +mtime -- $f)$2'
)

或者如果常见的字符始终是第 3 个第 7

autoload zmv # best in ~/.zshrc
zmodload zsh/stat

dest=~/Categories

categories=(Television Lightbulb Motocar)

mkdir -p -- $dest/$^categories

for c ($categories) (
  zmv -n "(**/)*$c[3,7]*(.*)" '$dest/$c/$c-$(
          zstat -F %FT%T%z +mtime -- $f)$2'
)

答案2

可能不是最有效的方法,但我会彻底解决问题,并将文件名中的字符串与目录相匹配,并且由于当前枚举是随机的,因此只需将它们计入即可保持唯一性。

homedir=~/Categories
eval homedir=$homedir

cats="Television Lightbulb Bananas Motorcar"
declare -A count

for cat in $cats; do if [ ! -d $homedir/$cat ]; then mkdir -p $homedir/$cat; fi; done

while read f; do
    r=${f##*/}
    r=${r%.*}
    r=$(grep -Po "[a-z]+" <<<$r)
    for cat in $cats; do
        if [ $(grep -i "$r" <<< $cat) ]; then
            ((count[$cat]++))
            mv "$f" $homedir/$cat/$cat-$(printf "%03g" ${count[$cat]}).${f##*.}
        fi
    done
done <<< $(find ./banana/ -type f) 

不匹配的内容将grep默默地退出循环,并留在原处以供稍后特别注意。

您想在文件名组合中包含的任何其他内容都可以输入,最后修改日期是

$(stat -c %Y $f)

ETC

相关内容