使用“bash”展开大括号

使用“bash”展开大括号

网上有很多关于此的文档,并且bash手册页非常好。即便如此,我还是不明白为什么这不起作用。显然我错过了一些东西......

我有一个包含 100 个文件的目录,名为file010, file020... file1000。我希望它们重命名为new00..99using 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,则需要调用mv100 次来重命名每个单独的文件。没有真正的解决办法。

file010要按数字顺序从到迭代文件,file1000您可以使用

for name in file{010..990..10} file1000
do
    # rest of code goes here
done

{010..990..10}一个大括号扩展,可扩展为字符串010、等020030最多以99010 为步长。每个此类字符串都将以字符串 为前缀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*

相关内容