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 (includesqmv
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.