Perl批量重命名文件序列号初始值设置指南

本文详细讲解了在使用Perl的rename命令进行批量重命名时,如何正确设置序列号的初始值。通过分析变量作用域和BEGIN块的使用,解决了所有文件被重命名为相同名称的问题,并提供了多种有效的解决方案。

如何在使用批量重命名设置序列编号时设置初始值?

在这个回答中,使用了以下命令:

1
rename -n 'our $i; s/_.*/sprintf("_%03d.png", $i++)/e' *.png

将文件从:

1
2
3
4
abc_128390.png
abc_138493.png
abc_159084.png
...

重命名为:

1
2
3
4
abc_001.png
abc_002.png
abc_003.png
...

我需要做完全相同的事情,但从28开始编号:

1
2
3
4
abc_028.png
abc_029.png
abc_030.png
...

但是当我改为:

1
rename -n 'our $i = 28; s/_.*/sprintf("_%03d.png", $i++)/e' *.png

它返回:

1
2
3
4
rename(abc_128390.png, abc_028.png)
rename(abc_138493.png, abc_028.png)
rename(abc_159084.png, abc_028.png)
...

所有文件都获得相同的名称。 为什么这次编号没有增加? 如何正确修改上述命令以实现我的需求?

解决方案

方法一:使用BEGIN块

our $i = 28;放在主脚本中不起作用,因为它会为每个文件名将$i重置为28 - rename对每个文件名执行一次主脚本中的每个语句。

您可以在BEGIN块中为变量设置初始值(或任何其他只需要在脚本首次执行时运行一次的设置代码)- 例如BEGIN {our $i = 28};

您仍然需要在BEGIN块和主脚本中使用our将变量声明为包全局变量,因为rename在严格模式下运行perl代码。

1
2
3
4
5
6
$ rename -n 'BEGIN {our $i = 28};
             our $i;
             s/_.*/sprintf("_%03d.png", $i++)/e' *.png
rename(abc_128390.png, abc_028.png)
rename(abc_138493.png, abc_029.png)
rename(abc_159084.png, abc_030.png)

注意:您不必每次使用变量时都用our声明它。在每个代码块中只声明一次,即在BEGIN中一次,在主脚本中一次 - 要么在代码块中首次使用之前,要么在块中首次使用时。这也有效:

1
2
$ rename -n 'BEGIN {our $i = 28};
             s/_.*/sprintf("_%03d.png", our $i++)/e' *.png

方法二:使用defined-or运算符

一个简单的方法是:

1
our $i //= 28;

这仍然将其声明为包全局变量以绕过strict,但仅在尚未定义时才分配28。

方法三:使用state变量

$i声明为state变量也可以,不需要BEGIN块,但建议避免使用,除非您对perl中的变量作用域有很好的理解:

1
2
3
4
5
$ rename -n 'state $i = 28;
             s/_.*/sprintf("_%03d.png", $i++)/e' *.png
rename(abc_128390.png, abc_028.png)
rename(abc_138493.png, abc_029.png)
rename(abc_159084.png, abc_030.png)

方法四:使用Perl主内部变量

这是使用Perl主内部变量的一种方法,不需要使用our全局变量:

1
rename -n 'BEGIN{$main::i = 28} s/_.*/sprintf("_%03d.png", $main::i++)/e' ./*.png

这里的解决方案是使用完全限定的标量变量$main::i(与在main包中时相同)。

方法五:使用zsh的zmv

使用zsh的zmv:

1
2
autoload -Uz
n=28; zmv -n '(*_)<->(.png)' '$1${(l[3][0])$((n++))}'

(与大多数rename实现一样,-n用于试运行)。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计