How to Move Files in Bash
Quick Answer: Move Files in Bash
To move a file in Bash, use the mv command: mv source destination. Moving is just renaming within the same directory or moving to a different directory. Use mv -i for interactive mode to prevent accidental overwrites.
Quick Comparison: File Moving Methods
| Method | Syntax | Best For | Safety |
|---|---|---|---|
| mv | mv source dest | Simple moves | Standard |
| mv -i | Interactive | Careful moves | Safe |
| mv -v | Verbose | Seeing progress | Feedback |
| cp + rm | Two commands | Complex logic | Controlled |
| rsync | Sync approach | Network moves | Advanced |
Bottom line: Use mv -i for safety, plain mv for scripts.
Method 1: Basic File Movement
Moving a file is simply relocating it from one directory to another while keeping its name the same. The mv command handles this with just source and destination arguments. It’s one of the fastest operations—on the same filesystem, it only updates directory entries, not copying data.
Move Single File to Directory
Here’s the fundamental pattern:
mv source.txt /backup/
This moves source.txt into the /backup/ directory, keeping its original name. The trailing slash on the directory is optional but makes your intent clear—you’re moving INTO that directory.
Move with Rename
You can move AND rename in one command:
mv /path/to/old_name.txt /backup/new_name.txt
The destination becomes both the directory AND the new filename. This is useful when you want to move and rename simultaneously.
Move Multiple Files
mv file1.txt file2.txt file3.txt /backup/
All three files move into /backup/, keeping their names. The last argument is always the destination when moving multiple files.
When to Use Basic Move
Use simple mv when:
- Moving single or multiple files
- You want the file to keep its name
- Destination directory already exists
- You’re confident about the operation
- You want speed (very fast on same filesystem)
Avoid it when:
- Destination might already contain the file (use
-i) - Moving directories with many files (use caution with
-r) - Crossing filesystems (might be slower than expected)
Method 2: Renaming Files
Renaming is just a special case of moving—moving a file within the same directory with a different name. Bash doesn’t have a separate rename command; mv handles both moving and renaming.
Simple Rename
mv old_name.txt new_name.txt
The file stays in the same directory but gets a new name. Simple and fast.
Batch Renaming
#!/bin/bash
# Rename all .txt files to .bak
for file in *.txt; do
[ -f "$file" ] || continue
new_name="${file%.txt}.bak"
mv "$file" "$new_name"
echo "Renamed: $file -> $new_name"
done
This loops through all .txt files and renames each one. The ${file%.txt} syntax removes the .txt extension, then .bak is added.
Test Batch Renaming First
Before running batch renames, always test what would be renamed:
# TEST: See what would be renamed
for file in *.txt; do
[ -f "$file" ] || continue
new_name="${file%.txt}.bak"
echo "Would rename: $file -> $new_name"
done
# Then actually do it
for file in *.txt; do
[ -f "$file" ] || continue
new_name="${file%.txt}.bak"
mv "$file" "$new_name"
done
This two-step approach prevents mistakes. Review the “Would rename” output before running the actual rename.
When to Use Renaming
Use mv for renaming when:
- Changing file extensions
- Updating naming conventions
- Preparing files for processing
- Removing problematic characters from names
- Batch processing with patterns
Method 3: Interactive Move (Safety Flag)
Use the -i flag to be prompted before overwriting. This prevents accidental data loss when the destination might already exist.
Move with Confirmation
mv -i file.txt /backup/file.txt
If file.txt already exists in /backup/, you get a prompt:
mv: overwrite '/backup/file.txt'?
Respond y to overwrite or n to skip.
When Overwrite Happens
Here’s the surprise many people miss: if you’re not explicit, mv WILL overwrite without asking:
# Dangerous: overwrites silently
mv file.txt /backup/file.txt # If file.txt exists there, it's gone
# Safe: asks first
mv -i file.txt /backup/file.txt
For critical files, always use -i or scripts should prevent overwrites explicitly.
When to Use Interactive Mode
Use -i when:
- Overwriting could cause problems
- You’re not 100% sure destination doesn’t have the file
- Critical systems where overwrites are dangerous
- Running interactively (not in automated scripts)
Don’t use it when:
- In scripts where you want guaranteed behavior
- Doing bulk operations (prompts get tedious)
- You’ve already verified destination is empty
Method 4: Non-Overwrite Mode
The -n flag prevents overwriting—if the destination exists, the move is silently skipped. This is safer than interactive mode for scripts.
Move Without Overwriting
mv -n file.txt /backup/file.txt
If file.txt already exists in /backup/, the move is skipped with no error or prompt. The script continues silently.
When Non-Overwrite Matters
# Merge directories without losing existing files
mv -n /source/* /destination/
This moves everything from source to destination, but if files already exist there, they’re left alone (source isn’t overwritten).
When to Use -n Flag
Use -n when:
- Automated scripts need predictable behavior
- You want to preserve existing files
- Doing incremental moves
- You don’t want prompts in unattended scripts
Method 5: Verbose Output
The -v flag shows exactly what’s being moved. Useful for seeing progress with many files or confirming operations.
Move with Progress Display
mv -v file.txt /backup/
Output:
'file.txt' -> '/backup/file.txt'
Combine with Other Flags
# Interactive and verbose
mv -iv file.txt /backup/
# Non-overwrite and verbose
mv -nv file.txt /backup/
Flags stack together for combined behavior.
When to Use -v Flag
Use -v when:
- Moving many files (see progress)
- Testing rename/move operations
- Creating logs of what happened
- Debugging why certain files didn’t move
Practical Examples
Example 1: Organize Downloads by File Type
#!/bin/bash
DOWNLOAD_DIR="$HOME/Downloads"
# Create subdirectories if they don't exist
mkdir -p "$DOWNLOAD_DIR"/{PDFs,Images,Videos,Documents,Other}
# Organize files
for file in "$DOWNLOAD_DIR"/*; do
# Skip if not a regular file
[ -f "$file" ] || continue
# Skip if already in a subdirectory
[ "$(dirname "$file")" = "$DOWNLOAD_DIR" ] || continue
case "$(basename "$file")" in
*.pdf)
mv "$file" "$DOWNLOAD_DIR/PDFs/"
echo "Moved PDF: $(basename $file)"
;;
*.jpg|*.png|*.gif|*.jpeg)
mv "$file" "$DOWNLOAD_DIR/Images/"
echo "Moved image: $(basename $file)"
;;
*.mp4|*.mkv|*.avi|*.mov)
mv "$file" "$DOWNLOAD_DIR/Videos/"
echo "Moved video: $(basename $file)"
;;
*.doc|*.docx|*.xlsx|*.txt)
mv "$file" "$DOWNLOAD_DIR/Documents/"
echo "Moved document: $(basename $file)"
;;
*)
mv "$file" "$DOWNLOAD_DIR/Other/"
;;
esac
done
echo "Organization complete"
This script automatically sorts downloads into folders based on file type.
Example 2: Rename with Timestamp
#!/bin/bash
# Add timestamp to filename while keeping extension
rename_with_timestamp() {
local file="$1"
local timestamp=$(date +%Y%m%d_%H%M%S)
local name="${file%.*}" # Remove extension
local ext="${file##*.}" # Get extension
local new_name="${name}_${timestamp}.${ext}"
mv "$file" "$new_name"
echo "Renamed: $file -> $new_name"
}
# Usage
rename_with_timestamp "report.txt"
# Result: report_20260221_143045.txt
Useful for creating dated backups before overwriting files.
Example 3: Safe Move with Verification
#!/bin/bash
safe_move() {
local source="$1"
local destination="$2"
# Verify source exists
if [ ! -e "$source" ]; then
echo "ERROR: Source not found: $source"
return 1
fi
# Check if destination exists
if [ -e "$destination" ]; then
read -p "Destination exists. Overwrite? (y/n) " -n 1 -r
echo
[[ ! $REPLY =~ ^[Yy]$ ]] && return 1
fi
# Ensure destination directory exists
dest_dir=$(dirname "$destination")
mkdir -p "$dest_dir" || return 1
# Perform the move
if mv -v "$source" "$destination"; then
echo "Move successful"
return 0
else
echo "Move failed"
return 1
fi
}
# Usage
safe_move "/tmp/file.txt" "/backup/file.txt"
This function checks everything before moving, creating directories as needed.
Example 4: Log Rotation
#!/bin/bash
rotate_log() {
local log_file="$1"
local archive_dir="${log_file%/*}/archive" # Get directory, add /archive
local timestamp=$(date +%Y%m%d_%H%M%S)
# Create archive directory if needed
mkdir -p "$archive_dir"
# Move current log to archive with timestamp
if [ -f "$log_file" ]; then
mv "$log_file" "$archive_dir/$(basename $log_file).$timestamp"
echo "Log rotated: $(basename $log_file)"
fi
# Create new empty log file with original permissions
touch "$log_file"
chmod 644 "$log_file"
}
# Usage
rotate_log "/var/log/myapp/app.log"
Essential for keeping log files manageable by archiving old ones.
Example 5: Conditional Move (Only if Safe)
#!/bin/bash
# Move only if destination doesn't exist
conditional_move() {
local source="$1"
local destination="$2"
if [ ! -f "$source" ]; then
echo "ERROR: Source not found"
return 1
fi
if [ -f "$destination" ]; then
echo "SKIP: Destination already exists"
return 2 # Different error code
fi
mv "$source" "$destination" && echo "Moved successfully"
}
conditional_move "/tmp/file.txt" "/backup/file.txt"
Different return codes signal different outcomes (success=0, source error=1, destination exists=2).
Example 6: Move and Deduplicate
#!/bin/bash
# Move files, skip if they already exist at destination
move_with_dedup() {
local source_dir="$1"
local dest_dir="$2"
mkdir -p "$dest_dir"
moved=0
skipped=0
for file in "$source_dir"/*; do
[ -f "$file" ] || continue
filename=$(basename "$file")
if [ -f "$dest_dir/$filename" ]; then
echo "SKIP (exists): $filename"
((skipped++))
else
mv "$file" "$dest_dir/"
echo "MOVED: $filename"
((moved++))
fi
done
echo "Completed: $moved moved, $skipped skipped"
}
move_with_dedup "/tmp/upload" "/home/archive"
Moves files while avoiding overwriting existing ones, keeping track of what happened.
Quick Reference
# Simple move
mv file.txt /backup/
# Rename
mv old.txt new.txt
# Move and rename
mv /old/path/old.txt /new/path/new.txt
# Interactive (ask before overwrite)
mv -i file.txt /backup/
# Verbose (show what's moving)
mv -v file.txt /backup/
# Don't overwrite
mv -n file.txt /backup/
# Combined flags
mv -inv file.txt /backup/
# Move multiple files
mv file1.txt file2.txt file3.txt /backup/
# Move all of a type
mv *.log /archive/
# Batch rename extension
for f in *.txt; do mv "$f" "${f%.txt}.bak"; done
Important Considerations
Filesystem Boundaries
Moving on the same filesystem is instant (just updates directory entries). But moving across filesystems actually copies, then deletes—much slower:
# Fast (same filesystem)
mv /home/user/file.txt /home/user/backup/
# Slow (different filesystem—actually copies and deletes)
mv /home/file.txt /mnt/usb/file.txt
Always Quote Filenames
# CORRECT: Handles spaces
mv "$old_file" "$new_file"
# WRONG: Breaks with spaces
mv $old_file $new_file # Fails if names have spaces
Exit Codes Matter in Scripts
if mv "$source" "$destination"; then
echo "Success"
else
echo "Failed (exit code: $?)"
fi
Success is exit code 0, failure is non-zero.
Summary
The mv command is your workhorse for file organization and renaming. Use plain mv when you’re confident, -i for interactive safety, and -n to prevent overwrites in scripts. Remember that renaming is just a special case of moving within the same directory. Always test batch operations before running them on real files, and be aware that moving across filesystems is slower than moving within the same filesystem.
#!/bin/bash
DOWNLOAD_DIR="/home/user/Downloads"
# Organize files by type
for file in "$DOWNLOAD_DIR"/*; do
[ -f "$file" ] || continue
case "$file" in
*.pdf)
mv "$file" "$DOWNLOAD_DIR/PDFs/"
;;
*.jpg|*.png|*.gif)
mv "$file" "$DOWNLOAD_DIR/Images/"
;;
*.mp4|*.mkv|*.avi)
mv "$file" "$DOWNLOAD_DIR/Videos/"
;;
*)
# Unknown type
mv "$file" "$DOWNLOAD_DIR/Other/"
;;
esac
done
Batch Renaming
Rename multiple files with a pattern:
#!/bin/bash
# Rename all .txt files to .bak
for file in *.txt; do
[ -f "$file" ] || continue
new_name="${file%.txt}.bak"
mv "$file" "$new_name"
echo "Renamed: $file -> $new_name"
done
# Output:
# Renamed: document1.txt -> document1.bak
# Renamed: document2.txt -> document2.bak
Renaming with Timestamps
Add timestamps to files:
#!/bin/bash
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
# Rename file with timestamp
mv important_file.txt "important_file_${TIMESTAMP}.txt"
# Result: important_file_20260221_143045.txt
Safe Move Function
Create a safe function that checks before moving:
#!/bin/bash
safe_move() {
local source="$1"
local dest="$2"
# Check if source exists
if [ ! -e "$source" ]; then
echo "ERROR: Source does not exist: $source"
return 1
fi
# Check if destination exists
if [ -e "$dest" ]; then
read -p "Destination exists. Overwrite? (y/n) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Move cancelled"
return 1
fi
fi
# Perform move
mv "$source" "$dest"
echo "Moved: $source -> $dest"
return 0
}
# Usage
safe_move "/tmp/file.txt" "/backup/file.txt"
Moving and Renaming Together
Move a file to a new location with a new name:
#!/bin/bash
# Move and rename in one command
mv /home/user/old_project /home/archive/new_project_name
# Move file to directory and rename it
mv document.txt /archive/document_final.txt
Conditional Move
Move only if destination doesn’t exist:
#!/bin/bash
source="/tmp/myfile.txt"
dest="/backup/myfile.txt"
if [ ! -f "$dest" ]; then
mv "$source" "$dest"
echo "File moved successfully"
else
echo "Destination already exists, skipping move"
fi
Practical Example: Log Rotation
#!/bin/bash
LOG_DIR="/var/log/myapp"
ARCHIVE_DIR="/var/log/myapp/archive"
# Move current log to archive and add timestamp
if [ -f "$LOG_DIR/app.log" ]; then
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
mv "$LOG_DIR/app.log" "$ARCHIVE_DIR/app_$TIMESTAMP.log"
# Create new empty log file
touch "$LOG_DIR/app.log"
echo "Log rotated at $(date)"
fi
Important Notes
mvon the same filesystem is fast (just updates directory entries)mvacross filesystems might copy and delete (slower)- Use
-fto force move without prompting (dangerous!) - Always test with
echofirst if renaming many files - Don’t forget quotes around filenames with spaces:
mv "old name.txt" "new name.txt" - Exit code is 0 on success, non-zero on failure
Quick Reference
# Basic move
mv file.txt /backup/
# Rename
mv old.txt new.txt
# Interactive (ask before overwrite)
mv -i file.txt /backup/
# Verbose (show what's moving)
mv -v file.txt /backup/
# Don't overwrite
mv -n file.txt /backup/
# Move and rename together
mv /old/path/old_name.txt /new/path/new_name.txt
# Move multiple files
mv file1.txt file2.txt file3.txt /backup/
# Move all files of a type
mv *.log /backup/
Summary
The mv command is essential for file management. Use it to move files between directories and rename them. Remember to use -i for safety when overwriting and test your commands before running them on multiple files.