78

我有一组名为:

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 终端中完成工作?我已经安装了重命名,但是使用以下命令会出错:

rename -n 's/(\w+) - (\d{1})x(\d{2})*$/S0$2E$3\.srt/' *.srt
4

8 回答 8

92

您忘记了星号前面的一个点:

rename -n 's/(\w+) - (\d{1})x(\d{2}).*$/S0$2E$3\.srt/' *.srt

在 OpenSUSE、RedHat、Gentoo 上,您必须使用 Perl 版本的rename. 这个答案显示了如何获得它。在 Arch 上,这个包被称为perl-rename.

于 2012-08-04T15:31:58.623 回答
35

真的很酷 lil diddy。查找 + 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最终的结果是:

OldName.ext    NewName.ext
OldName.ext    NewName.ext
OldName.ext    NewName.ext
OldName.ext    NewName.ext

我的系统上没有rename现成的 Perl。


它是如何工作的?

  1. find . -type f输出文件路径(或文件名......您可以在这里控制正则表达式处理的内容!)
  2. -p打印正则表达式处理的文件路径,-e执行内联脚本
  3. print $_首先打印原始文件名(独立于-p
  4. -d "\n"通过换行符而不是默认空格字符剪切输入
  5. -n2每行打印两个元素
  6. mv获取上一行的输入

我的首选方法,尽管更先进。

假设我想将所有“.txt”文件重命名为“.md”文件:

find . -type f -printf '%P\0' | perl -0 -l0 -pe 'print $_; s/(.*)\.txt/$1\.md/' | xargs -0 -n 2 mv

这里的神奇之处在于管道中的每个进程都支持用作分隔符的空字节 (0x00),而不是空格或换行符。上述方法使用换行符作为分隔符。并不是说我试图在find .不使用子流程的情况下轻松支持。在这里要小心(find在运行正则表达式匹配或更糟糕的破坏性命令之前,您可能需要检查输出mv)。

它是如何工作的(删节以仅包括上面的更改)

  1. In find:-printf '%P\0'仅打印没有路径的文件名,后跟空字节。根据您的用例进行调整 - 无论是匹配文件名还是整个路径。
  2. in perland xargs: -0stdin 分隔符是空字节(而不是空格)
  3. In perl: -l0stdout 分隔符是空字节(八进制 000)
于 2018-01-16T11:54:19.320 回答
12

编辑:找到了一种更好的方法来列出文件而不使用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]\+\).*$/S0\1E\2.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]\+\).*$/S0\1E\2.srt/'`
  mv "$file" "$newname"
done
于 2017-02-02T00:52:31.377 回答
10

并非每个发行版都rename提供支持上述示例中使用的正则表达式的实用程序 - RedHat、Gentoo 及其衍生产品等。

尝试使用的替代方法是perl-renamemmv

于 2015-05-18T11:17:01.920 回答
9

使用mmv(大规模移动?)

它简单但有用:*通配符匹配任何字符串(不带斜线)并?匹配要匹配的字符串中的任何字符。在替换字符串中使用#X以引用第 X 个通配符匹配。

在你的情况下:

mmv 'Friends - 6x?? - Tow *.srt' 'S06E#1#2.srt'

这里表示由(匹配#1和#2)#1#2捕获的两个数字。 因此进行了以下替换:??

Friends - 6x?? - Tow *           .srt    matches
Friends - 6x03 - Tow Ross' Denial.srt    which is replaced by
            ↓↓
        S06E03.srt

mmv还提供[和匹配。];

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

有关更多信息,请参见手册页

就个人而言,我用它来填充数字,以便在按字典顺序排序时以所需的顺序显示编号的文件(例如,1 出现在 10 之前):file_?.extfile_0#1.ext

于 2017-12-02T11:34:29.643 回答
6

如果您的 linux 不提供rename,您还可以使用以下内容:

find . -type f -name "Friends*" -execdir bash -c 'mv "$1" "${1/\w+\s*-\s*(\d)x(\d+).*$/S0\1E\2.srt}"' _ {} \;

我经常使用这个片段在我的控制台中使用正则表达式执行替换。

我对 shell 的东西不是很好,但据我了解这段代码,它的解释是:你的find的搜索结果将被传递给你的搜索结果的 bash-command ( bash -c )作为源文件在$1内。接下来的目标是子shell中替换的结果,其中$1内容(这里:参数替换{ 1 //find/replace}中的 1 )也将是您的搜索结果。{}将其传递给-execdir的内容

更好的解释将不胜感激:)

请注意:我只复制粘贴了您的正则表达式;请先使用示例文件对其进行测试。根据您的系统,您可能需要将 \d 和 \w 更改为 [[:digit:]] 或 [[:alpha:]] 等字符类。但是, \1 应该适用于组。

于 2017-10-09T14:07:53.140 回答
3

我认为最简单和通用的方法是使用for loop sedand mv。首先,您可以在管道中检查您的正则表达式替换:

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

如果它打印正确的替换,只需将其放入for loopwithmv

for i in $(ls *.srt); do 
    mv $i $(echo $i | sed -E 's/.* ([0-9])x([0-9]{2}) .*(\.srt)/S\1E\2\3/g') 
    done
于 2020-12-07T21:27:18.330 回答
1

您可以使用rnm

rnm -rs '/\w+\s*-\s*(\d)x(\d+).*$/S0\1E\2.srt/' *.srt

解释:

  1. -rs: 替换表单的字符串/search_regex/replace_part/modifier
  2. (\d)(\d+)in(\d)x(\d+)是两个捕获的组(\1\2分别)。

更多例子在这里

于 2016-05-07T08:43:06.457 回答