Automated File Renaming in Linux: How to Safely Move Files with mv and Handle Name Conflicts


1 views

When consolidating multiple image directories into one location, file name conflicts are inevitable. The standard mv command in Linux simply overwrites existing files without warning, which could lead to data loss when dealing with important image collections.

While there's no built-in mvsafe command, we have several approaches:

# Using GNU coreutils (version 8.0+)
cp --backup=numbered *.jpg /targetpath/
rm *.jpg

The --backup=numbered option automatically appends .~1~, .~2~ etc. to conflicting files.

For more control over naming, create a bash function in your .bashrc:

mvsafe() {
    local dest=$2/$(basename "$1")
    if [[ -e "$dest" ]]; then
        local counter=1
        while [[ -e "${dest%.*}_$counter.${dest##*.}" ]]; do
            ((counter++))
        done
        mv "$1" "${dest%.*}_$counter.${dest##*.}"
    else
        mv "$1" "$dest"
    fi
}

For complex scenarios, a Python script offers more flexibility:

#!/usr/bin/env python3
import os
import shutil
import sys

def safe_move(src, dst_dir):
    filename = os.path.basename(src)
    base, ext = os.path.splitext(filename)
    counter = 1
    dest = os.path.join(dst_dir, filename)
    
    while os.path.exists(dest):
        dest = os.path.join(dst_dir, f"{base}_{counter}{ext}")
        counter += 1
    
    shutil.move(src, dest)

if __name__ == "__main__":
    safe_move(sys.argv[1], sys.argv[2])

Combine our solution with find for batch processing:

# Using the bash function
find . -type f -name "*.jpg" -exec bash -c 'mvsafe "$0" /targetpath/' {} \;

# Using the Python script
find . -type f -name "*.jpg" -exec python3 mvsafe.py {} /targetpath/ \;

Consider these specialized utilities if you frequently need this functionality:

  • renameutils package (includes qmv for bulk renaming)
  • mmv (mass move and rename tool)
  • rsync with --ignore-existing or --backup options

When consolidating files from multiple directories, filename collisions are inevitable. The standard mv command overwrites existing files without warning, which can lead to data loss when merging directories containing images, logs, or other files with common naming patterns.

The --backup option in GNU coreutils provides built-in protection:

mv --backup=numbered source_file target_directory/

This creates numbered backups (file.txt.~1~, file.txt.~2~) when conflicts occur. For more control, combine with find:

find . -type f -name "*.jpg" -exec mv --backup=numbered {} /targetpath/ \;

When you need specific renaming patterns (like suffix _2, _3), consider these approaches:

Option 1: Using mmv (Mass Move)

mmv "*.jpg" "/targetpath/#1_#2.jpg"

Option 2: Bash Function

mvsafe() {
    local src=$1 dest=$2
    if [[ -e "$dest/$(basename "$src")" ]]; then
        local base=${src%.*} ext=${src##*.}
        local counter=1
        while [[ -e "$dest/${base}_$counter.$ext" ]]; do
            ((counter++))
        done
        mv "$src" "$dest/${base}_$counter.$ext"
    else
        mv "$src" "$dest"
    fi
}

For complex scenarios, this Python 3 script provides maximum flexibility:

#!/usr/bin/env python3
import os
import shutil
import sys

def safe_move(src, dst_dir):
    basename = os.path.basename(src)
    name, ext = os.path.splitext(basename)
    counter = 1
    dest_path = os.path.join(dst_dir, basename)
    
    while os.path.exists(dest_path):
        dest_path = os.path.join(dst_dir, f"{name}_{counter}{ext}")
        counter += 1
    
    shutil.move(src, dest_path)

if __name__ == "__main__":
    if len(sys.argv) != 3:
        print(f"Usage: {sys.argv[0]} source destination_directory")
        sys.exit(1)
    safe_move(sys.argv[1], sys.argv[2])

For enterprise environments, consider these additional features:

  • Atomic operations using temp files
  • MD5 checksum verification
  • Permission preservation
  • Progress reporting

Example with rsync (preserves metadata):

rsync --progress --ignore-existing --remove-source-files *.jpg /targetpath/

When processing millions of files:

find . -type f -print0 | xargs -0 -P8 -n1 mvsafe /targetpath/

The -P8 enables parallel processing with 8 threads.