1

运行以下脚本来重命名当前文件夹中的所有 .jpg 文件有时效果很好,但它通常会删除它正在重命名的一个或多个文件。我将如何编写脚本来重命名文件而不在过程中删除它们?这是在 Mac OSX 10.8 上运行,使用 GNU bash,版本 3.2.48

这是一个示例文件列表,我将更改以进行说明:

原始文件

red.jpg
blue.jpg
green.jpg

如果计数器设置为 5,则重命名文件

file_5.jpg
file_6.jpg
file_7.jpg

相反,我通常会丢失一个或多个文件

#!/bin/bash  

counter=5

for file in *.jpg; do

    echo renaming "$file" to "file_${counter}.jpg";
    mv "$file" "file_${counter}.jpg";
    let "counter+=1";

done

**更新**

它似乎不再删除文件,但输出仍然不如预期。例如:

file_3.jpg
file_4.jpg

变成

file_3.jpg
file_5.jpg

当计数器设置为 4 时,当预期输出为

file_4.jpg
file_5.jpg

-

#!/bin/bash  

counter=3

for file in *.jpg; do

    if [[ -e file_${counter}.jpg ]] ; then
        echo Skipping "$file", file exists.
    else
        echo renaming "$file" to "file_${counter}.jpg"
        mv "$file" "file_${counter}.jpg"
    fi

    let "counter+=1"

done
4

5 回答 5

10

问题是某些文件已经具有与目标名称相对应的名称。例如,如果有文件

file_1.jpg
file_7.jpg

并且您从 开始,在第一步中counter=7覆盖file_7.jpg,然后将其重命名为.file_1.jpgfile_8.jpg

您可以使用它mv -n来防止破坏(如果支持),或者在运行命令之前测试是否存在

if [[ -e file_${counter}.jpg ]] ; then
    echo Skipping "$file", file exists.
else
    mv "$file" "file_${counter}.jpg"
fi
于 2013-08-14T14:58:11.180 回答
2

我认为您正在对 glob 的一个明显问题感到困惑。如果 glob 与 file_2.jpg 匹配,它将尝试创建 file_file_2.jpg(我的意思不是字面意义上的,只是您将重新处理已处理的文件)。要解决这个问题,您需要确保您的初始 glob 表达式与您已移动的文件不匹配:

shopt -s extglob

i=0
for f in !(file_*).jpg ; do
    while [[ -e "file_${i}.jpg" ]] ; do
        (( i++ ))
    done

    mv -v "$f" "file_$i.jpg"
    (( i++ ))
done
于 2013-08-14T15:07:08.890 回答
1

choroba 说的是对的。您还可以使用:

mv "$file" "file_${counter}.jpg" -n

当目标文件名已经存在时简单地忽略移动,或者

mv "$file" "file_${counter}.jpg" -i

询问是否应该覆盖。

于 2013-08-14T15:04:32.750 回答
1

而不是迭代*.jpg你应该跳过你已经重命名的文件,即file_[0-9]*.jpg像这样运行你的循环:

counter=5

while read file; do
   echo renaming "$file" to "file_${counter}.jpg";
   mv -n "$file" "file_${counter}.jpg";
   let "counter+=1";
done < <(find . -maxdepth 1 -name "*.jpg" -not -name "file_[0-9]*.jpg")
于 2013-08-14T15:05:51.603 回答
1

另一种方法是继续计数,直到文件不存在:

#!/bin/bash  

counter=1
shopt -s extglob

for file in *.jpg; do
    [[ $file == ?(*/)file_+([[:digit:]]).jpg ]] && continue

    until
        newname=file_$(( counter++ )).jpg
        [[ ! -e $newname ]]
    do
        continue
    done

    echo "renaming $file to $newname.";

    mv -i "$file" "$newname" ## Remove the -i option if you think it's safe already.
done

递归做事时:

#!/bin/bash  

shopt -s  extglob    
counter=1

while read file; do
    dirprefix=${file%%+([^/])

    until
        newfile=$dirprefix/file_$(( counter++ )).jpg
        [[ ! -e $newfile ]]
    do
        continue
    done

    echo "renaming $file to $newfile."

    mv -i "$file" "$newfile" ## Remove the -i option if you think it's safe already.
done < <(find -type f -name '*.jpg' -and -not -regex '^.*/file_[0-9]\+$')
于 2013-08-14T15:20:58.203 回答