A powerful bash script that recursively finds files with a specific name in a source folder and copies them to corresponding directories in a destination folder while preserving the directory structure.
This script is perfect for copying configuration files (like .env, .config.json, etc.) across different folder hierarchies while maintaining the same relative paths. It automatically creates any missing directories in the destination folder with zero configuration needed.
- 🔍 Recursively searches for files by name in all subfolders
- 📁 Preserves directory structure when copying
- ➕ Automatically creates missing destination directories
- 💬 Interactive prompts for user input
- 🎨 Colored output for better readability
- 📊 Summary report showing files found and copied
- 🖥️ POSIX shell compatible
| Platform | Support | Notes |
|---|---|---|
| macOS | ✅ Full Support | Works natively on all macOS versions with Bash/Zsh |
| Linux | ✅ Full Support | Works on all Linux distributions with Bash/Sh |
| Windows | Use Windows Subsystem for Linux or Git Bash |
Both macOS and Linux are fully compatible with this script since they share the same Unix-like architecture:
- Same core: Both use POSIX-compliant shells and Unix tools
- Identical behavior: Output, directory structure, and copying mechanisms work identically
- No platform-specific code: The script uses only standard Unix commands (
find,mkdir,cp) - No special configuration: No need to adjust the script for different platforms
The only minor difference is the default shell:
- macOS: Uses
zshby default (since macOS Catalina), butbashandshwork perfectly - Linux: Typically uses
bashby default
- Shell: Bash, Sh, Zsh, or any POSIX-compatible shell
- Unix Tools:
find,mkdir,cp(standard on all macOS and Linux systems) - Permissions: Read access to source folder, write access to destination folder
./copier.shYou'll be prompted for:
- Filename or pattern to search for (e.g.,
.env,*.docx,config.*) - Source folder path
- Destination folder path
./copier.sh "*.PDF"Prompts for source and destination folders only.
./copier.sh "*.PDF" ~/projects/source ~/projects/backupNo prompts - direct execution with all parameters specified.
The script supports flexible pattern matching:
| Pattern | Matches | Example |
|---|---|---|
.env |
Exact filename | .env file only |
*.PDF |
Any file ending with .PDF | document.PDF, report.PDF |
*.docx |
Any Word document | file.docx, resume.docx |
config.* |
Files starting with "config" | config.json, config.yaml, config.xml |
test* |
Files starting with "test" | test.py, test-1.txt, test_data.csv |
Case-Insensitive Search: All patterns are case-insensitive by default, so *.PDF matches .pdf, .Pdf, and .PDF files.
graph TD
A["📁 source/"] -->|Find .env| B["🔍 Copy with structure"]
A --> C["📄 .env"]
A --> D["📁 backend/"]
D --> E["📄 .env"]
D --> F["📁 auth/"]
A --> G["📁 frontend/"]
C -.->|Copy| H["📁 backup/"]
E -.->|Copy| I["📁 backup/backend/"]
H --> J["📄 .env"]
I --> K["📄 .env"]
style H fill:#e1f5e1
style I fill:#e1f5e1
style B fill:#fff3cd
Command:
./copier.sh ".env" ~/projects/source ~/projects/backupBefore:
~/projects/source/
├── .env # Root level config
├── backend/
│ ├── .env # Backend config
│ └── auth/
└── frontend/
After:
~/projects/backup/
├── .env # Copied from root
├── backend/
│ └── .env # Copied from backend
└── frontend/ # Created (no .env here)
Wildcards allow you to match multiple files with patterns. Case-insensitive matching is enabled by default!
# Copy all PDF files (case-insensitive - .PDF, .pdf, .Pdf all match)
./copier.sh "*.PDF" ~/Desktop/Pendrive ~/Desktop/backup
# Copy all Word documents
./copier.sh "*.docx" ~/Documents/source ~/Documents/backup
# Copy all files starting with "config"
./copier.sh "config.*" ~/app/config-source ~/app/config-backup
# Copy all tar.gz archives
./copier.sh "*.tar.gz" ~/archives/source ~/archives/destinationExample with output:
$ sh copier.sh "*.PDF" ~/Desktop/Pendrive ~/Desktop/mini_serv
Searching for '*.PDF' files in: /Users/vkatasonov/Desktop/Pendrive
✓ Copied: DELE.PDF → DELE.PDF
✓ Copied: subdirs/report.pdf → subdirs/report.pdf
✓ Copied: docs/manual.PDF → docs/manual.PDF
Summary:
Found: 3 '*.PDF' file(s)
Copied: 3 '*.PDF' file(s)Key Features:
- 🔍 Case-insensitive:
*.PDF,*.pdf, and*.Pdfall match the same files - 📁 Directory structure preserved: Files keep their relative directory paths
- 💾 Actual filenames preserved: Files are copied with their real names, not the pattern
- ✅ Accurate summary: Counter displays number of files found and copied
./copier.sh ".config.json" ~/app/source ~/app/destination./copier.sh "setup.sql" ~/databases/old ~/databases/newEnter filename to search for (e.g., .env):
.env
Enter source folder path:
~/Desktop/ft_transcendence_local_copy
Enter destination folder path:
~/Desktop/ft_transcendence
Searching for '.env' files in: /home/user/Desktop/ft_transcendence_local_copy
✓ Copied: .env → .env
✓ Copied: backend/.env → backend/.env
✓ Created directory: /home/user/Desktop/ft_transcendence/auth-service
✓ Copied: auth-service/.env → auth-service/.env
Summary:
Found: 3 '.env' file(s)
Copied: 3 '.env' file(s)
- ⚡ Overwrites files: The script will replace existing files without prompting. Backup important files first!
- 🏠 Tilde expansion: Paths like
~/Documents/projectare fully supported - 🔐 Permissions: Script needs read access to source and write access to destination
- 🔍 Hidden files: Works perfectly with hidden files (like
.env)
| Issue | Solution |
|---|---|
| "Source folder does not exist" | Check that the folder path is correct and accessible |
| "No files found" | Verify filename is correct (include dot prefix for hidden files like .env). Test with: find ~/source -name ".env" |
| Permission denied | Ensure read permissions on source and write permissions on destination. May need elevated privileges |
| Not working on macOS/Linux | Script is fully compatible with both platforms. Ensure the script is executable: chmod +x copier.sh |
MIT License © 2026 vkatasonov