waspinator
waspinator

Reputation: 6826

why does the mv command in bash delete files?

running the following script to rename all .jpg files in the current folder works well sometimes, but it often deletes one or more files it is renaming. How would I write a script to rename files without deleting them in the process? This is running on Mac OSX 10.8 using GNU bash, version 3.2.48

this is an example file listing I would change for illustration:

original files

red.jpg
blue.jpg
green.jpg

renamed files if counter is set to 5

file_5.jpg
file_6.jpg
file_7.jpg

instead I get usually lose one or more files

#!/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

** UPDATE **

it no longer seems to be deleting files, but the output is still not as expected. for example:

file_3.jpg
file_4.jpg

turns into

file_3.jpg
file_5.jpg

when counter is set to 4, when the expected output is

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

Upvotes: 1

Views: 1904

Answers (5)

konsolebox
konsolebox

Reputation: 75568

Another way is to continue your counting until a file does not exist:

#!/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

When doing things recursively:

#!/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]\+$')

Upvotes: 1

Craig
Craig

Reputation: 4399

I think you are glazing over an obvious problem with the glob. If the glob matches file_2.jpg, it will try and create file_file_2.jpg (I don't mean that in the literal sense, just that you will be reprocessing files you already processed). To solve this, you need to make sure your initial glob expression doesn't match the files you have already moved:

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

Upvotes: 2

anubhava
anubhava

Reputation: 785856

Instead of iterating over *.jpg you should skip your already renamed files i.e. file_[0-9]*.jpg and run your loop like this:

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")

Upvotes: 1

H.D.
H.D.

Reputation: 4454

What choroba said is correct. You can also use:

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

to simply neglect the move when the destination filename already exists, or

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

to ask whether it should overwrite or not.

Upvotes: 1

choroba
choroba

Reputation: 242123

The problem is that some of the files already have names corresponding to the target names. For example, if there are files

file_1.jpg
file_7.jpg

and you start with counter=7, you overwrite file_7.jpg with file_1.jpg in the first step, and then rename it to file_8.jpg.

You can use mv -n to prevent clobbering (if supported), or test for existence before running the command

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

Upvotes: 10

Related Questions