TidyBatch

How to organize your Downloads folder by file type

Turn a Downloads folder with hundreds of loose files into Images/, Documents/, Videos/, Spreadsheets/, Archives/ and Installers/ in one go.

Two rules for any script that moves files: look at the plan before anything moves, and never let a file replace one that is already there (an older Images/screenshot.png, for example). Both scripts below follow them.

Windows: PowerShell (built in)

Open PowerShell, go to the folder with cd $HOME\Downloads, and paste this. As written it only shows the plan:

$preview = $true   # change to $false to actually move the files
$types = @{
  Images       = '.jpg', '.jpeg', '.png', '.gif', '.webp', '.heic'
  Videos       = '.mp4', '.mov', '.mkv', '.avi'
  Documents    = '.pdf', '.doc', '.docx', '.odt', '.txt'
  Spreadsheets = '.xls', '.xlsx', '.ods', '.csv'
  Archives     = '.zip', '.rar', '.7z'
  Installers   = '.exe', '.msi'
}
Get-ChildItem -File | ForEach-Object {
  $file = $_
  $dir = $types.Keys | Where-Object { $types[$_] -contains $file.Extension } | Select-Object -First 1
  if (-not $dir) { return }
  if ($preview) { "$($file.Name)  ->  $dir\" }
  else {
    New-Item -ItemType Directory -Force -Path $dir | Out-Null
    Move-Item -LiteralPath $file.FullName -Destination $dir
  }
}

The plan looks like this (extensions match in any case, so .JPG counts as an image):

bank export.csv  ->  Spreadsheets\
clip.MP4  ->  Videos\
Holiday photo.JPG  ->  Images\
invoice.pdf  ->  Documents\
photos.zip  ->  Archives\
screenshot.png  ->  Images\
setup.exe  ->  Installers\

Happy with it? Paste it again with $preview = $false. If a file with the same name is already in the target folder, Move-Item shows a red error for that file and leaves both files alone. Tested in PowerShell 7.4.

macOS and Linux: a small bash script

Save this as organize.sh in your home folder:

#!/usr/bin/env bash
# Sort the files in the current folder into sub-folders by type.
# "bash organize.sh" only shows the plan; "bash organize.sh apply" moves the files.
shopt -s nocasematch
for f in *; do
  [ -f "$f" ] || continue
  case "$f" in
    *.jpg|*.jpeg|*.png|*.gif|*.webp|*.heic) dir=Images ;;
    *.mp4|*.mov|*.mkv|*.avi)                dir=Videos ;;
    *.pdf|*.doc|*.docx|*.odt|*.txt)         dir=Documents ;;
    *.xls|*.xlsx|*.ods|*.csv)               dir=Spreadsheets ;;
    *.zip|*.rar|*.7z|*.tar|*.gz)            dir=Archives ;;
    *.exe|*.msi|*.dmg|*.pkg|*.deb)          dir=Installers ;;
    *) continue ;;
  esac
  if [ "$1" = apply ]; then
    mkdir -p "$dir" && mv -n -- "$f" "$dir/"
  else
    echo "$f  ->  $dir/"
  fi
done

Then run it from the folder you want to sort (on macOS run it with bash as shown, even though the default shell is zsh):

cd ~/Downloads
bash ~/organize.sh          # preview
bash ~/organize.sh apply    # move the files

mv -n never overwrites: a file whose name is already taken in the target folder simply stays where it is, so anything left behind after the run is a name clash to check by hand.

Want an undo? TidyBatch Pro

tidybatch organize does the same sort with a preview by default, gives clashing names a _1 suffix instead of skipping them, puts unknown types in Other/, and records everything so one command puts it all back. Real output on the same test folder (which already had an Images/screenshot.png):

$ tidybatch organize ./Downloads
  bank export.csv    ->  Spreadsheets/bank export.csv
  clip.MP4           ->  Videos/clip.MP4
  Holiday photo.JPG  ->  Images/Holiday photo.JPG
  invoice.pdf        ->  Documents/invoice.pdf
  notes              ->  Other/notes
  photos.zip         ->  Archives/photos.zip
  screenshot.png     ->  Images/screenshot_1.png
  setup.exe          ->  Installers/setup.exe

8 file(s) would change.
Dry run: nothing was changed. Add --apply to do it.

Add --apply to do it, and tidybatch undo ./Downloads to restore every file to where it was (the folders it created are removed again). Other ways to sort:

tidybatch organize ./Downloads --by ext             # PDF/, JPG/, ZIP/ …
tidybatch organize ./Archive --by date -r           # 2024/08/ by modified date
tidybatch organize ./Camera --by taken -r           # 2023/07/ by photo date taken

organize is part of TidyBatch Pro (one-time purchase, ready-to-run apps for Windows and Linux). The two scripts above are free.

Which one should you use?

PowerShell / bash scriptTidyBatch Pro
Preview before moving✓✓ default
Never overwrites✓ clashes are skipped✓ clashes get _1
Undo afterwards— (move back by hand)✓ tidybatch undo
By date, by photo date taken, by extensionedit the script✓ --by
Pricefreepaid, one-time

Related: find duplicate files safely →

Related: how undo works →