使用正则表达式通过 zsh 脚本重建文件名

使用正则表达式通过 zsh 脚本重建文件名

我下载带有模式的文件

Konto_12334567890-Auszug_YYYY_00MM.pdf

并想将其保存在路径中

.../Belege YYYY/Belege YYYY MM/Kontoauszug.pdf

问题是如何从原始文件名中提取年份 YYYY 和月份 MM 并将其放入新文件名路径的文件夹名称中。

我在名为 的变量中获得了文件名(没有路径)$filename。我有另一个变量,$dest用于路径和$filename_new新文件名(在本例中: Constant Kontoauszug)。

我的第一个想法是:删除之前和包含的所有内容,Auszug_并将前四位数字放入一个变量($year)中,将最后两位数字.pdf放入另一个变量($month)中。也许有更好的解决方案...

所以我可以这样构建路径:

DEST="/Users/Belege/Belege $year/Belege $year $month/"

我只需要得到$year$month充满。

我怎样才能做到这一点?

答案1

zmv最简单的方法是通过辅助函数移动它们,例如

dtmv () {                                                                     
    mkdir -p -- $2:h && mv -- $@
}
autoload zmv
zmv -n -P dtmv 'Konto_12334567890-Auszug_(*)_00(*).pdf' '/Users/Belege_$1/Belege_$1_$2/Kontoauszug.pdf'

s(*)创建可在第二个参数中使用的反向引用,如$1$2
此处zmvwith-P执行函数dtmv而不是mv。该函数创建目录,然后将文件移动到新创建的目录。对于每个文件,都会传递原始文件和替换文件。

笔记-n代表试运行所以上面只会打印要运行的命令。删除 来-n实际运行该命令。我还建议不要使用带空格的文件名,但如果您坚持让它们用空格替换所有下划线:

zmv -n -P dtmv 'Konto_12334567890-Auszug_(*)_00(*).pdf' '/Users/Belege $1/Belege $1 $2/Kontoauszug.pdf'

如果由于某种原因必须使用变量,有多种方法可以实现。由于文件名具有固定长度并匹配相同的模式,我个人会使用子字符串,例如

year=${filename: -13:-9}
month=${filename: -6:-4}

:注意第一个冒号和减号之间的空格-
另一种方法是将字符串拆分_(用 删除扩展名后:r),因此年份是第三个元素,月份是第四个元素减去前两个字符:

year=${${(s[_])filename:r}[3]}
month=${${${(s[_])name:r}[4]}:2}

答案2

假设您的文件名始终是您显示的方式,并且 YYYY 和 MM 是数字,您可以执行以下操作:

filename=Konto_12334567890-Auszug_2022_0005.pdf     
year=$(cut -d_ -f3 <<<"$filename")
month=$(cut -d_ -f4 <<<"$filename" | sed -e 's/^00//' -e  's/.pdf$//')
mv -- "$filename" "/Users/Belege/Belege $year/Belege $year $month/"

然而,我无论如何强调路径和文件名中带有空格是多么糟糕的想法。这些只会使您以后处理这些文件的工作变得更加复杂。所以我强烈建议你做这样的事情:

mv -- "$filename" "/Users/Belege/Belege_$year/Belege_${year}_$month/"

答案3

要回答有关如何在 中提取 YYYY 和 MM 的更通用问题Konto_12334567890-Auszug_YYYY_00MM.pdf,您可以执行以下操作:

set -o extendedglob
file='Konto_12334567890-Auszug_YYYY_00MM.pdf'
if [[ $file = (#b)*_(<1900-2100>)_00(<1-12>).pdf ]]; then
  year=$match[1] month=$match[2]
fi

<1-12>匹配表示 1 到 12 范围内的数字(因此包括 1、01、0000000001)的任何十进制数字序列。<->一位或多位十进制数字的匹配和序列,与 Extendedglob 相同[0-9]##

(#b)启用back 引用,因此里面的部分(...)可以在$match.

相关内容