Sort by File Extension - Bash Script
Source: Dev.to
Overview
This Bash script organizes the contents of a directory by file extension. It creates a sorted_files folder inside the source directory and, for each distinct extension found, generates a subdirectory containing copies of the matching files.
Key features
- Works recursively on all files (excluding hidden ones).
- Handles case‑insensitive extensions (e.g.,
JPEGandjpeg). - Places files without an extension into a
no_extensionfolder. - Preserves original file timestamps and metadata.
- Leaves the source files untouched; only copies are created.
- Provides a progress indicator and a summary report of how many files were processed per extension.
Typical use cases include sorting music collections (.mp3, .ogg, .wav), documents (.pdf, .docx), videos (.mkv, .mp4), and images (.jpg, .png).
Usage
./sort_by_extension.sh [source_directory]
- If
source_directoryis omitted, the script defaults to the current working directory. - The resulting structure will be created at
/sorted_files.
Script
#!/bin/bash
# Recursive File Extension Sorter
# Organizes files by their extensions into a sorted_files directory
# Default to current directory if no argument is provided
SOURCE_DIR="${1:-$(pwd)}"
# Verify that the source directory exists
if [ ! -d "$SOURCE_DIR" ]; then
echo "Error: Directory '$SOURCE_DIR' does not exist."
exit 1
fi
# Create the sorted_files directory
SORTED_DIR="$SOURCE_DIR/sorted_files"
mkdir -p "$SORTED_DIR"
# Initialize counters
declare -A extension_counts
total_files=0
# Scan and process files
echo "Scanning and organizing files in '$SOURCE_DIR'..."
echo "This may take a while for large directories."
echo ""
# Find all non‑hidden files
find "$SOURCE_DIR" -type f ! -path '*/\.*' | while read -r file; do
# Skip files already in the sorted directory
if [[ "$file" == "$SORTED_DIR"* ]]; then
continue
fi
# Extract filename and extension
filename=$(basename "$file")
if [[ "$filename" == *.* ]]; then
extension="${filename##*.}"
extension=$(echo "$extension" | tr '[:upper:]' '[:lower:]') # normalize to lowercase
else
extension="no_extension"
fi
# Ensure the extension directory exists
mkdir -p "$SORTED_DIR/$extension"
# Copy file while preserving timestamps
cp -p "$file" "$SORTED_DIR/$extension/"
# Update counters
((total_files++))
((extension_counts[$extension]++))
# Show progress every 100 files
if (( total_files % 100 == 0 )); then
echo "Processed $total_files files..."
fi
done
# Summary report
echo ""
echo "Sorting complete! Processed $total_files files."
echo "Files organized by extension:"
# List counts alphabetically
for ext in $(printf '%s\n' "${!extension_counts[@]}" | sort); do
echo " $ext: ${extension_counts[$ext]} files"
done
echo ""
echo "All files have been copied to: $SORTED_DIR"
echo "Note: Original files remain unchanged."