How to Copy Multiple Files
Quick Answer: Copy Multiple Files
To copy multiple files in Bash, use cp with wildcards: cp *.txt /destination/. For more control, use a loop: for f in file1 file2 file3; do cp "$f" /destination/; done. For complex selections, combine with find.
Quick Comparison: Multiple File Copying Methods
| Method | Syntax | Best For | Complexity |
|---|---|---|---|
| Wildcards | cp *.txt dest/ | Pattern matching | Very simple |
| for loop | for f in list; do cp ... | Explicit lists | Moderate |
| find + cp | find . -name ... + cp | Complex criteria | Moderate |
| brace expansion | cp {file1,file2,file3} dest/ | Selected files | Simple |
| xargs + cp | find ... | xargs cp | Large lists | Advanced |
Bottom line: Use wildcards for simple patterns, use find for complex criteria.
Copy multiple files efficiently using various methods in Bash. Whether you’re copying specific file types, files matching patterns, or files from a list, understanding different approaches helps you choose the right tool for each situation.
Method 1: Using Wildcards and Glob Patterns
Wildcards provide a quick way to copy multiple files matching a pattern.
# Copy all .txt files to destination
cp *.txt /destination/
# Copy all files in current directory
cp * /destination/
# Copy specific pattern with brace expansion
cp file_{1,2,3}.txt /destination/
# Copy all hidden files
cp .* /destination/
# Copy all files starting with 'log'
cp log* /backup/
# Copy multiple extensions
cp *.{txt,log,csv} /destination/
Example output:
# Before
$ ls -la
file1.txt
file2.txt
file3.txt
$ cp *.txt /destination/
# After
$ ls -la /destination/
file1.txt
file2.txt
file3.txt
Method 2: Copy with Array and Loop
Using an array with a loop provides better control and error handling.
#!/bin/bash
files=("file1.txt" "file2.txt" "file3.txt")
destination="/backup"
for file in "${files[@]}"; do
if [ -f "$file" ]; then
cp "$file" "$destination/"
echo "Copied: $file"
else
echo "Warning: File not found - $file"
fi
done
Output:
Copied: file1.txt
Copied: file2.txt
Copied: file3.txt
Method 3: Copy from List File
Read a file containing a list of files to copy.
#!/bin/bash
list_file="$1"
destination="${2:-.}"
if [ ! -f "$list_file" ]; then
echo "List file not found: $list_file"
exit 1
fi
# Read file list and copy
while IFS= read -r file; do
[ -z "$file" ] && continue # Skip empty lines
[[ "$file" =~ ^#.* ]] && continue # Skip comments
if [ -f "$file" ]; then
cp "$file" "$destination/"
echo "Copied: $file"
else
echo "Warning: File not found - $file"
fi
done < "$list_file"
echo "Copy complete"
Input file (filelist.txt):
./documents/report.pdf
./documents/budget.xlsx
./spreadsheets/sales.csv
# This is a comment
./media/photo.jpg
Output:
Copied: ./documents/report.pdf
Copied: ./documents/budget.xlsx
Copied: ./spreadsheets/sales.csv
Copied: ./media/photo.jpg
Copy complete
Method 4: Using find with -exec
The find command is powerful for complex filtering.
# Find and copy specific files
find . -name "*.log" -exec cp {} /backup/ \;
# More efficiently with xargs
find . -name "*.log" -print0 | xargs -0 cp -t /backup/
# Copy files modified in last 7 days
find . -type f -mtime -7 -exec cp {} /backup/ \;
# Copy files larger than 10MB
find . -type f -size +10M -exec cp {} /backup/ \;
Method 5: Copy with Recursion
Copy files from subdirectories while maintaining structure.
# Copy with directory structure preserved
cp -r /source/directory /destination/
# Copy only specific file types recursively
find /source -type f -name "*.txt" -exec cp {} /destination/ \;
# Copy with tar to preserve permissions and structure
tar -cf - /source/*.txt | tar -xf - -C /destination/
Practical Examples
Example 1: Backup Specific Files
#!/bin/bash
backup_dir="/backup/$(date +%Y%m%d)"
mkdir -p "$backup_dir"
# Define files to backup
files=(
"/etc/hostname"
"/etc/hosts"
"/root/.bashrc"
"/root/.bash_profile"
)
for file in "${files[@]}"; do
if [ -f "$file" ]; then
cp "$file" "$backup_dir/"
echo "Backed up: $file"
else
echo "Warning: $file not found"
fi
done
echo "Backup complete: $backup_dir"
Output:
Backed up: /etc/hostname
Backed up: /etc/hosts
Backed up: /root/.bashrc
Backed up: /root/.bash_profile
Backup complete: /backup/20241225
Example 2: Copy Recent Logs
#!/bin/bash
# Copy log files modified today
archive_dir="/var/log/archive"
mkdir -p "$archive_dir"
find /var/log -type f -name "*.log" -mtime 0 -exec cp {} "$archive_dir/" \;
echo "Recent logs archived to $archive_dir"
Example 3: Copy with Progress Tracking
#!/bin/bash
source_files=(
"file1.iso"
"file2.iso"
"file3.iso"
)
destination="/external_drive/"
total=${#source_files[@]}
current=0
for file in "${source_files[@]}"; do
((current++))
if [ -f "$file" ]; then
echo "[$current/$total] Copying: $file"
cp "$file" "$destination/"
echo "Success"
else
echo "[$current/$total] Error: $file not found"
fi
done
echo "Copy operation complete: $current/$total files"
Output:
[1/3] Copying: file1.iso
Success
[2/3] Copying: file2.iso
Success
[3/3] Copying: file3.iso
Success
Copy operation complete: 3/3 files
Example 4: Copy with Verification
#!/bin/bash
copy_and_verify() {
local source="$1"
local dest="$2"
if [ ! -f "$source" ]; then
echo "Error: Source file not found - $source"
return 1
fi
if ! cp "$source" "$dest/"; then
echo "Error: Copy failed for $source"
return 1
fi
# Verify file size matches
source_size=$(stat -c%s "$source")
dest_file="$dest/$(basename "$source")"
dest_size=$(stat -c%s "$dest_file")
if [ "$source_size" -eq "$dest_size" ]; then
echo "Verified: $source"
return 0
else
echo "Error: Size mismatch for $source"
rm "$dest_file"
return 1
fi
}
# Usage
for file in *.zip; do
copy_and_verify "$file" "/backup/"
done
Example 5: Copy Multiple File Types
#!/bin/bash
# Copy multiple file types with different handling
archives_dir="./archives"
documents_dir="./documents"
images_dir="./images"
mkdir -p "$archives_dir" "$documents_dir" "$images_dir"
# Copy archives
cp *.{zip,tar,gz} "$archives_dir/" 2>/dev/null
# Copy documents
cp *.{pdf,doc,docx,txt} "$documents_dir/" 2>/dev/null
# Copy images
cp *.{jpg,png,gif,bmp} "$images_dir/" 2>/dev/null
echo "Files organized into directories"
Example 6: Selective Copy with Exclusion
#!/bin/bash
source_dir="$1"
dest_dir="$2"
# Copy all except temp files and caches
find "$source_dir" -type f \
! -name "*.tmp" \
! -name ".cache" \
! -path "*/node_modules/*" \
-exec cp {} "$dest_dir/" \;
echo "Selective copy complete"
Performance Comparison
For copying multiple files:
| Method | Speed | Memory | Best For |
|---|---|---|---|
| Wildcard glob | Fastest | Low | Simple patterns, many files |
| Array loop | Very Fast | Medium | Controlled, error handling |
| find with xargs | Very Fast | Low | Complex filtering |
| find with -exec | Fast | Low | Very large file counts |
Best choice: Use cp *.ext /dest/ for simplicity, find for complex patterns.
Important Considerations
Destination Must Exist
Most copy operations require the destination directory to exist:
# Create destination if needed
mkdir -p /destination/
# Then copy
cp file1.txt file2.txt /destination/
Avoiding Overwriting
Use the -n flag to prevent overwriting:
# Don't overwrite existing files
cp -n *.txt /destination/
Preserving Attributes
Use -p to preserve permissions and timestamps:
cp -p *.txt /destination/
Recursive Copy with Structure
# Preserve directory structure
cp -r /source/* /destination/
Handling Spaces in Filenames
Always quote variables when dealing with spaces:
for file in "${array[@]}"; do
cp "$file" "$destination/" # Quotes are important!
done
Key Points
- Use wildcards for quick simple copies
- Use loops for control and error handling
- Use find for complex filtering and large file sets
- Always create destination directory first
- Quote variables to handle spaces in filenames
- Verify copies of critical files
- Use appropriate flags (-r for recursion, -p for preserve)
Quick Reference
# Copy all txt files
cp *.txt /destination/
# Copy with loop
for file in *.txt; do
cp "$file" /destination/
done
# Copy from find
find . -name "*.log" -exec cp {} /backup/ \;
# Copy with xargs (efficient)
find . -name "*.txt" | xargs cp -t /destination/
# Copy recursively
cp -r /source/ /destination/
# Copy and preserve attributes
cp -rp /source/ /destination/