网上有很多关于此的文档,并且bash
手册页非常好。即便如此,我还是不明白为什么这不起作用。显然我错过了一些东西......
我有一个包含 100 个文件的目录,名为file010
, file020
... file1000
。我希望它们重命名为new00..99
using mv
(好吧,mvg
实际上,但是两者都有相同的输出)。当我运行以下任何一个时,我得到target 'new99' is not a directory
(总是最后一个)。
我缺少什么?
id@machine ~/temp/test ls
file010 file090 file160 file240 file320 file400 file480 file560 file640 file720 file800 file880 file960
file020 file100 file170 file250 file330 file410 file490 file570 file650 file730 file810 file890 file970
file030 file1000 file180 file260 file340 file420 file500 file580 file660 file740 file820 file900 file980
file040 file110 file190 file270 file350 file430 file510 file590 file670 file750 file830 file910 file990
file050 file120 file200 file280 file360 file440 file520 file600 file680 file760 file840 file920
file060 file130 file210 file290 file370 file450 file530 file610 file690 file770 file850 file930
file070 file140 file220 file300 file380 file460 file540 file620 file700 file780 file860 file940
file080 file150 file230 file310 file390 file470 file550 file630 file710 file790 file870 file950
id@machine ~/temp/test mv {*,new{00..99}}
/usr/local/bin/mvg: target 'new99' is not a directory
✘ id@machine ~/temp/test mv {file{010..1000..10},new{00..99}}
/usr/local/bin/mvg: target 'new99' is not a directory
✘ id@machine ~/temp/test mv {file*,new{00..99}}
/usr/local/bin/mvg: target 'new99' is not a directory
答案1
你还缺少什么?如何mv
运作。
当您提供正好 2 个文件时,您会将第一个文件名重命名为第二个文件名。
对于超过 2 个文件,最后一个参数被视为目录,所有前面的参数都是要移动到那里的文件。
参考手册页。
要重命名文件,您需要一个循环:
i=0
for file in *; do
mv -v "$file" "$(printf 'new%02d' $i)"
((i++))
done
一个想法:如果你有超过 100 个文件怎么办?如何避免硬编码%02d
?
files=(*)
num=$(( ${#files[@]} - 1 ))
size=${#num}
for idx in "${!files[@]}"; do
mv -v "${files[idx]}" "$(printf 'new%0*d' $size $idx)"
done
答案2
如果要使用 重命名 100 个文件mv
,则需要调用mv
100 次来重命名每个单独的文件。没有真正的解决办法。
file010
要按数字顺序从到迭代文件,file1000
您可以使用
for name in file{010..990..10} file1000
do
# rest of code goes here
done
是{010..990..10}
一个大括号扩展,可扩展为字符串010
、等020
,030
最多以990
10 为步长。每个此类字符串都将以字符串 为前缀file
。我们file1000
在末尾添加,因为它的数字不太符合模式(一位数字太长)。
要重命名循环中的文件,我们可以保留一个计数器,从零开始计数。然后,新文件名被构造为前缀,file
后跟计数器当前值给出的零填充的两位整数。
将其添加到上面的循环中:
count=0
for name in file{010..990..10} file1000
do
printf -v newname 'file%.2d' "$(( count++ ))"
mv -- "$name" "$newname"
done
或者,我们可以使用算术循环来代替大括号扩展,for
如下所示:
for (( i = 1; i <= 100; ++i )); do
printf -v name 'file%.3d' "$(( i * 10 ))"
printf -v newname 'file%.2d' "$(( i - 1 ))"
mv -- "$name" "$newname"
done
使用 Perlrename
实用程序而不是mv
:
rename -n -v 's/file(\d+)/sprintf "file%.2d", ($1\/10 - 1)/e' file*
这会将 Perl s///
(替换)表达式应用于file*
当前目录中匹配的每个文件名。该表达式匹配子字符串后面的数字file
,并使用它来计算新的文件名数字(它除以 10 并减 1)。
删除-n
以“真实”运行命令(-n
是一个“试运行”选项)。
一个更干净的变体,不用于/e
评估替换字符串,并且只提到file
一次:
rename -n -v '/(file)(\d+)/; $_ = sprintf "%s%.2d", $1, ($2/10 - 1)' file*