我想用零填充数字重命名文件,同时保留扩展名。
示例
a.abc
b.cde
c.xyz
重命名为
001.abc
002.cde
003.xyz
:~/x$ rename -n -v 's/.+/our $i; sprintf("%03d.jpg", 1+$i++)/e' *
#output>
rename(a.abc, 001.jpg)
rename(b.cde, 002.jpg)
rename(c.xyz, 003.jpg)
#then
:~/x$ echo "a.abc"
a.abc
:~/x$ echo ${_##*.}
#output>
abc
so I tried>
:~/x$ rename -n -v 's/.+/our $i; sprintf("%03d.${_##*.}", 1+$i++)/' *
Global symbol "$i" requires explicit package name (did you forget to declare "my $i"?) at (user-supplied code).
Missing right curly or square bracket at (user-supplied code), within string
syntax error at (user-supplied code), at EOF
任何建议使用“改名”命令?
答案1
rename -n -v 'our $n; my $zn=sprintf("%03d", ++$n); s/[^.]*/$zn/' *
这可能会达到您的预期。而不是放置 Perl 代码里面替换,我们运行它前替代。
正则表达式[^.]*
将匹配任何长度的字符串,直到(但不包括)文件名中的第一个点。
为了匹配到最后的点,使用.*\.
替代,并将点插入替换侧:
rename -n -v 'our $n; my $zn=sprintf("%03d", ++$n); s/.*\./$zn./' *
请注意,这也会重命名目录。
或者,使用简单的 shell 循环,假设您希望按照*
shell glob 扩展文件的顺序枚举文件,并且使用bash
:
n=1
for filename in *; do
[ ! -f "$filename" ] && continue
zn=$( printf '%03d' "$n" )
mv -i -- "$filename" "$zn.${filename##*.}"
n=$(( n + 1 ))
done
这还会跳过任何不引用常规文件(或指向该文件的符号链接)的名称。除此之外,还有如下很接近上面的Perlrename
变体,它保留一个计数器 ( n
) 和计数器的零填充变体 ( zn
)。
该变量n
是一个简单的计数器,并且$zn
具有与 相同的值$n
,但作为一个用零填充的三位数。
的值$zn.${filename##*.}
将扩展到零填充的数字,后跟一个点和原始文件名的最终文件名后缀。如果原始文件名中存在多个点,则直到最后的点将被零填充的数字替换。更改##
为#
替换最多第一的点。
这假设您仅对当前目录中的文件运行循环。
答案2
你可以做
rename -n -v 'our $i; s{^\./.+?(\.[^.]*)?\z}{sprintf "%03d%s", ++$i, $1}se' ./*
./
前缀./*
:对于某些变体来说rename
是必需的,否则对于以-
..+?
:匹配至少一个字符,因为我们不希望将前导.
(对于隐藏文件,仅在dotglob
启用 shell 选项时相关)被视为扩展名分隔符。(\.[^.]*)?
:也重命名不带扩展名的文件(如.foo
或foo
)\z
: 匹配主题的结尾。更一般地rename
,您不想使用 ,$
因为它匹配主题末尾或尾随换行符之前。s
标志:确保.
也匹配换行符,该换行符与文件名中的任何字符一样有效。e
flag:替换是一个perl表达式,所以我们可以sprintf
在那里使用。