运行以下脚本来重命名当前文件夹中的所有.jpg文件有时效果很好,但它经常删除它重命名的一个或多个文件。如何在不删除文件的情况下编写脚本来重命名文件?这是在Mac OSX 10.8上使用GNU bash,版本3.2.48
运行的这是一个示例文件列表,我将更改为插图:
原始文件
red.jpg
blue.jpg
green.jpg
如果counter设置为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
答案 0 :(得分:10)
问题是某些文件已经具有与目标名称对应的名称。例如,如果有文件
file_1.jpg
file_7.jpg
,您从counter=7
开始,在第一步中使用file_7.jpg
覆盖file_1.jpg
,然后将其重命名为file_8.jpg
。
您可以使用mv -n
来阻止clobbering(如果支持),或者在运行命令之前测试是否存在
if [[ -e file_${counter}.jpg ]] ; then
echo Skipping "$file", file exists.
else
mv "$file" "file_${counter}.jpg"
fi
答案 1 :(得分: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
答案 2 :(得分:1)
什么choroba说是正确的。您也可以使用:
mv "$file" "file_${counter}.jpg" -n
在目标文件名已存在时忽略移动,或
mv "$file" "file_${counter}.jpg" -i
询问是否应该覆盖。
答案 3 :(得分: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")
答案 4 :(得分: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]\+$')