![使用正则表达式通过 zsh 脚本重建文件名](https://linux22.com/image/214692/%E4%BD%BF%E7%94%A8%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E9%80%9A%E8%BF%87%20zsh%20%E8%84%9A%E6%9C%AC%E9%87%8D%E5%BB%BA%E6%96%87%E4%BB%B6%E5%90%8D.png)
我下载带有模式的文件
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
。
此处zmv
with-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)
启用b
ack 引用,因此里面的部分(...)
可以在$match
.