如何将文件从一种递增模式重命名为另一种递增模式?

如何将文件从一种递增模式重命名为另一种递增模式?

我有一组文件,其名称如下:

048. banana.mkv
049. apple.mkv
050. mango.mkv
051. pear.mkv
052. grape.mkv

我需要按照以下命名约定重命名这些文件

01. banana.mkv
02. apple.mkv
03. mango.mkv
04. pear.mkv
05. grape.mkv

问题是我需要重命名数百个文件,并且需要从多个组开始01并递增。通常我会rename批量重命名文件。在这种情况下,我一直使用qvm更改每个文件名。肯定有更简单的方法。

答案1

使用基于 perl 的rename实用程序:

$ rename -n 's/^(\d+)/sprintf "%02d", $1-47/e' *.mkv
rename(048. banana.mkv, 01. banana.mkv)
rename(049. apple.mkv, 02. apple.mkv)
rename(050. mango.mkv, 03. mango.mkv)
rename(051. pear.mkv, 04. pear.mkv)
rename(052. grape.mkv, 05. grape.mkv)

这里的技巧是替换e上的修饰符s/pattern/replacement/- 它让你将替换字符串作为 perl 表达式进行评估 - 包括$1-47通过 进行算术和填充格式sprintf-n当您确信它正在做正确的事情时,请删除。

如果你只有一个 shell,那么:

$ for f in *.mkv; do 
    n="${f%%.*}"
    printf -v newf '%02d.%s' "$((10#$n-47))" "${f#*.}"
    echo mv -- "$f" "$newf" 
  done
mv -- 048. banana.mkv 01. banana.mkv
mv -- 049. apple.mkv 02. apple.mkv
mv -- 050. mango.mkv 03. mango.mkv
mv -- 051. pear.mkv 04. pear.mkv
mv -- 052. grape.mkv 05. grape.mkv

echo一旦您确认它做了正确的事情,就将其删除。


拥有zshzmv

% autoload zmv
% setopt expanded_glob
%
% zmv -n '(*[0-9])(*.mkv)' '${(l:2::0:)$(( $1-47 ))}$2'
mv -- '048. banana.mkv' '01. banana.mkv'
mv -- '049. apple.mkv' '02. apple.mkv'
mv -- '050. mango.mkv' '03. mango.mkv'
mv -- '051. pear.mkv' '04. pear.mkv'
mv -- '052. grape.mkv' '05. grape.mkv'

在这种情况下,数字格式化是使用l(字母 ell)扩展修饰符完成的 - from man zshexpn

   l:expr::string1::string2:
          Pad the resulting words on the left.  Each word  will  be  trun‐
          cated if required and placed in a field expr characters wide.

与 一样rename,删除-n即可真正改变名称。

答案2

我认为起始号码并不总是这样的048,在这种情况下,您可能需要一个可以在每个目录中运行的命令(无需修改)并且始终执行正确的事情。

您可以在每个目录中运行此命令:

file-rename -n 's/^\d{3}\./sprintf "%02d.", ++our $i/e' -- *.mkv

这类似于steeldriver 的回答,主要区别在于它会帮你确定从哪里开始。还有其他细微的差别。注意如果输入编号中有空白,这将填补输出编号中的空白,这可能是也可能不是您想要的。也就是说,如果您的文件为048. banana.mkv049. apple.mkv051. mango.mkv,则输出将是01. banana.mkv02. apple.mkv03. mango.mkv不是 04. mango.mkv)。

如上所述,由于该选项,该命令不会重命名任何文件-n。相反,它显示了它执行。如果您对此感到满意,您可以再次运行它而无需-n

file-rename 's/^\d{3}\./sprintf "%02d.", ++our $i/e' -- *.mkv

您可能没有该file-rename命令。如果没有,那么您很可能没有rename命令,或者(这就是我建议使用的原因file-renamerename您的rename命令可能完全不同。如果没有file-rename(或者如果您更喜欢将其写为rename并且没有),您可以通过安装软件包来获取它rename

sudo apt update && sudo apt install rename

怎么运行的

当你的 shell 将 glob 模式扩展*.mkv为文件名列表时,结果列表按字典顺序排列。具体含义取决于您当前的语言环境,并且通常它与数字顺序不同,即使两者都适用。但是,由于您的文件名从最开始就已编号,并且所有数字都在左侧用0s 填充,因此不会出现此问题,并且您的 shell 将扩展*.mkv为按数字顺序排列的路径列表。

由于 shell 会处理这个问题,剩下的预防措施就是确保file-rename避免更改任何文件以三位数字序列开头,后跟.

在替换表达式中s/^\d{3}\./sprintf "%02d.", ++our $i/e

  • ^\d{3}\.是一个正则表达式。它与文件名开头 ( ) 处紧接着三个 ( ) 位数字 ( ).之后\.出现的文字 ( ){3}匹配。\d^

  • sprintf "%02d.", ++our $i是 Perl 代码。

    它使用全局变量$i,如果尚未看到,则将其引入(our)。$i以零值开始,但每次使用时都会递增,在使用它之前立即递增(前缀++会这样做)。因此,对于每个文件,它都采用值 1、2、3 等。

    sprintf用于格式化它,如果需要的话,在左边填充零,宽度为 2,后跟文字.. (.只需要在正则表达式中进行转义,否则它将匹配任何字符,而不是在替换表达式中进行转义。

  • e最后导致表达式为评估作为 Perl 代码生成替换结果。如果没有这个e,则以 开头的实际文本sprintf将被替换到每个文件名中,而不是将该文本作为 Perl 代码进行求值的结果。

文件名不是以三位数字开头,后面跟着 a 的文件.不会被重命名,也不会导致文件$i数量增加。文件名不是以后缀结尾的,一开始.mkv就不会被传递。file-rename

自动化

您可能只想对每个目录运行一次,因为听起来您只有少数几个目录。但是如果您想自动执行,您可以。这可以通过 来完成find,尽管它比乍一看更棘手和更复杂,因为路径看起来像find(例如,使用-execdir您将获得类似 的路径./048. banana.mkv),并且因为/-exec会拆分为多个命令(不希望重置)在目录非常大的情况下(您没有,但这是另一个必须考虑的因素)。-execdir+$i

因此您可能只想使用 shell 循环来运行它:

for d in dir1 dir2; do
    printf '%s:\n' "$d"
    (cd -- "$d" && file-rename -n 's/^\d{3}\./sprintf "%02d.", ++our $i/e' -- *.mkv)
done

(这对于包含大量文件的目录也不起作用*.mkv,但它会为这些目录提供错误消息,而不是执行错误的操作。)

替换dir1 dir2为包含要重命名的文件的实际目录列表。

这将产生如下输出:

dir1:
rename(048. banana.mkv, 01. banana.mkv)
rename(049. apple.mkv, 02. apple.mkv)
rename(050. mango.mkv, 03. mango.mkv)
rename(051. pear.mkv, 04. pear.mkv)
rename(052. grape.mkv, 05. grape.mkv)
dir2:
rename(099. foo.mkv, 01. foo.mkv)
rename(100. bar.mkv, 02. bar.mkv)
rename(101. baz.mkv, 03. baz.mkv)

如果看起来不错,您可以-n像以前一样删除 。(您仍然会看到目录名称标题,但看不到行rename(..., ...)。如果您希望在实际重命名期间也看到这些,您可以将选项传递-vfile-rename,即替换-n-v,而不是仅仅删除-n。不过,这可能会使注意到任何错误消息变得更加困难。)

进一步阅读

  • 在 Ubuntu 中批量重命名文件;rename 命令的简要介绍(经过奥利) 展示并解释了几种使用方法rename,包括sprintf

    这适用于当前的 Perl 重命名器file-rename和旧的prename。(在最新的 Ubuntu 版本中,file-renameprename是相同的,但在较旧的版本中,它们有所不同,并且行为略有不同。)在 Ubuntu 中,rename默认情况下 不存在或存在解析为其中一个的符号链接。它不适用于rename.ul,这是某些系统上的另一个实用程序(如果您在 Ubuntu 上配置它),当您运行 时会运行rename

  • 有关 Perl 中正则表达式的信息,我建议perldoc perlrequickperldoc perlre. 这些涵盖了表达式的语法s/

  • 有关正则表达式的一般信息,我建议https://www.regular-expressions.info

相关内容