在 Linux 中使用正则表达式重命名文件



我有一组文件,命名如下:

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

find +

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

<小时 />

它是如何工作的?

  1. find . -type f输出文件路径(或文件名...您可以在此处控制正则表达式处理的内容!
  2. -p打印由正则表达式处理的文件路径,-e执行内联脚本
  3. print $_首先打印原始文件名(独立于-p(
  4. -d "n" 通过换行符而不是默认空格字符剪切输入
  5. -n2每行打印两个元素
  6. 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这样的破坏性命令(。

工作原理(删节后仅包括上面的更改(

  1. find中:-printf '%P'仅打印不带路径后跟空字节的文件名称。根据您的用例进行调整 - 无论是匹配文件名还是整个路径。
  2. perlxargs中:-0标准分隔符是空字节(而不是空格(
  3. 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_?.extfile_0#1.ext

<小时 />

mmv还提供按[];匹配。

您不仅可以批量重命名,还可以批量移动,复制,附加链接文件。

有关详细信息,请参阅手册页!

编辑: 找到了一种更好的方法来列出文件,而无需使用IFSls,同时仍然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-renamemmv .

如果您的 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 sedmv。首先,您可以在管道中检查正则表达式替换:

ls *.srt | sed -E 's/.* ([0-9])x([0-9]{2}) .*(.srt)/S1E23/g'

如果它打印了正确的替换,只需将其放在带有mvfor 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

解释:

  1. -rs:替换/search_regex/replace_part/modifier形式的字符串
  2. (d)x(d+) (d)(d+)是两个被俘的群体(分别为12(。

更多例子在这里。

如果使用 rnr,则命令为:

rnr -f '.*(d{1})x(d{2}).*' 'S0${1}E${2}.str' *.srt

rnr的好处是能够撤消命令。

相关内容

  • 没有找到相关文章

最新更新