我有一组文件,命名如下:
Friends - 6x03 - Tow Ross' Denial.srt
Friends - 6x20 - Tow Mac and C.H.E.E.S.E..srt
Friends - 6x05 - Tow Joey's Porshe.srt
我想像下面这样重命名它们
S06E03.srt
S06E20.srt
S06E05.srt
我应该怎么做才能在 Linux 终端中完成工作?我已经安装了重命名,但 U 使用以下方法出现错误:
rename -n 's/(w+) - (d{1})x(d{2})*$/S0$2E$3.srt/' *.srt
你忘了星号前面的点:
rename -n 's/(w+) - (d{1})x(d{2}).*$/S0$2E$3.srt/' *.srt
在OpenSUSE,RedHat,Gentoo上,你必须使用Perl版本的rename
。这个答案显示了如何获得它。在 Arch 上,该包称为 perl-rename
。
perl + xargs + mv
xargs -n2
使得每行打印两个参数成为可能。当与Perl的print $_
(首先打印$STDIN(结合使用时,它构成了一个强大的重命名工具。
find . -type f | perl -pe 'print $_; s/input/output/' | xargs -d "n" -n2 mv
perl -pe 'print $_; s/OldName/NewName/' | xargs -n2
的结果最终是:
OldName1.ext NewName1.ext
OldName2.ext NewName2.ext
OldName3.ext NewName3.ext
OldName4.ext NewName4.ext
我的系统上没有现成的 Perl rename
。
它是如何工作的?
-
find . -type f
输出文件路径(或文件名...您可以在此处控制正则表达式处理的内容! -
-p
打印由正则表达式处理的文件路径,-e
执行内联脚本 -
print $_
首先打印原始文件名(独立于-p
( -
-d "n"
通过换行符而不是默认空格字符剪切输入 -
-n2
每行打印两个元素 -
mv
获取上一行的输入
我更喜欢的方法,尽管更先进。
假设我想将所有".txt"文件重命名为".md"文件:
find . -type f -printf '%P ' | perl -0 -l0 -pe 'print $_; s/(.*).txt/$1.md/' | xargs -0 -n 2 mv
这里的魔术在于管道中的每个进程都支持用作分隔符的空字节 (0x00(,而不是空格或换行符。上述第一种方法使用换行符作为分隔符。请注意,我试图在不使用子流程的情况下轻松支持find .
。在这里要小心(你可能想在通过正则表达式匹配之前检查find
的输出,或者更糟的是,像mv
这样的破坏性命令(。
工作原理(删节后仅包括上面的更改(
- 在
find
中:-printf '%P '
仅打印不带路径后跟空字节的文件名称。根据您的用例进行调整 - 无论是匹配文件名还是整个路径。 - 在
perl
和xargs
中:-0
标准分隔符是空字节(而不是空格( perl
:-l0
标准分隔符是空字节(八进制 000(
使用 mmv (mass-move?(
它简单但很有用:*
通配符匹配任何字符串(不带/
(,?
匹配字符串中要匹配的任何字符。在替换字符串中,使用 #N
引用第 N 个通配符匹配项。
在您的情况下:
mmv 'Friends - 6x?? - Tow *.srt' 'S06E#1#2.srt'
在这里,#1#2
表示??
捕获的两个数字(匹配 #1 和 #2(.
因此,正在进行以下替换:
The pattern string: 'Friends - 6x?? - Tow * .srt'
matches this file: Friends - 6x03 - Tow Ross' Denial.srt
↓↓
will be renamed to: S06E03.srt
就个人而言,我用它来填充数字,以便在按字典顺序排序时编号文件以所需的顺序出现(例如,1.
出现在10.
之前(:file_?.ext
→ file_0#1.ext
mmv
还提供按[
和]
和;
匹配。
您不仅可以批量重命名,还可以批量移动,复制,附加和链接文件。
有关详细信息,请参阅手册页!
编辑:
找到了一种更好的方法来列出文件,而无需使用IFS
和ls
,同时仍然sh
合规。
我会为此做一个 shell 脚本:
#!/bin/sh
for file in *.srt; do
if [ -e "$file" ]; then
newname=`echo "$file" | sed 's/^.*([0-9]+)x([0-9]+).*$/S01E2.srt/'`
mv "$file" "$newname"
fi
done
以前的脚本:
#!/bin/sh
IFS='
'
for file in `ls -1 *.srt`; do
newname=`echo "$file" | sed 's/^.*([0-9]+)x([0-9]+).*$/S01E2.srt/'`
mv "$file" "$newname"
done
并非每个发行版都提供支持上述示例中使用的正则表达式的rename
实用程序 - RedHat,Gentoo及其衍生产品等。
尝试使用的替代方案是 perl-rename
和 mmv
.
如果您的 Linux 不提供重命名,您还可以使用以下方法:
find . -type f -name "Friends*" -execdir bash -c 'mv "$1" "${1/w+s*-s*(d)x(d+).*$/S01E2.srt}"' _ {} ;
我经常使用此代码片段在我的控制台中使用正则表达式执行替换。
我不太擅长shell的东西,但据我理解这段代码,它的解释是这样的:你的搜索结果将被传递给一个bash命令(bash -c(,你的搜索结果将在$1内作为源文件。 下面的目标是子外壳内替换的结果, 其中 $1 的内容(此处:在您的参数替换 {1//find/replace} 中只有 1(也将是您的搜索结果。{} 将其传递给 -execdir 的内容
更好的解释将不胜感激:)
请注意:我只复制粘贴了您的正则表达式;请先使用示例文件进行测试。 根据您的系统,您可能需要将 \d 和 \w 更改为字符类,如 [[:d igit:]] 或 [[:alpha:]]。 但是,\1 应该适用于组。
我认为最简单和通用的方法将是使用for loop
sed
和mv
。首先,您可以在管道中检查正则表达式替换:
ls *.srt | sed -E 's/.* ([0-9])x([0-9]{2}) .*(.srt)/S1E23/g'
如果它打印了正确的替换,只需将其放在带有mv
的for loop
中
for i in $(ls *.srt); do
mv $i $(echo $i | sed -E 's/.* ([0-9])x([0-9]{2}) .*(.srt)/S1E23/g')
done
使用正则表达式重命名
它非常容易安装(与其他工具不同(:
pip3 install regex-rename
使用以下命令进行重命名:
regex-rename "(d{1})x(d{2})" "S01E2.srt" --rename
首先尝试"干运行"模式(不带--rename
标志(,以在实际重命名之前检查它是否看起来不错。它显示与每个组匹配的内容,以便您可以调试正则表达式,直到它正常为止。它需要 2 个参数:匹配器和替换模式,没有奇怪的s/.../.../
语法。另外,我懒得做完整的比赛,它只是适合季节+剧集模式。
我自己做了,因为我看到没有像这样的像样的工具。我很想听听你的反馈。
您可以使用 rnm:
rnm -rs '/w+s*-s*(d)x(d+).*$/S01E2.srt/' *.srt
解释:
-
-rs
:替换/search_regex/replace_part/modifier
形式的字符串 -
(d)x(d+)
(d)
和(d+)
是两个被俘的群体(分别为1
和2
(。
更多例子在这里。
如果使用 rnr,则命令为:
rnr -f '.*(d{1})x(d{2}).*' 'S0${1}E${2}.str' *.srt
rnr
的好处是能够撤消命令。