Sort Folders Into Alphabetic Sub-Folders

Scratching my own itch. I have a bunch of directories which I want moved into alphabetic sub-directories. This is handy is you have a bunch of MP3s, books, or other catalogued files.

This bash script moves a top level directory (and all the files and subdirectories under it), to a folder based on the (upper-case) version of the first character of the directory name.

for dir in */ ; do
    mkdir -p ${start^^}
    mv "$dir" ${start^^}

Save that as, make it executable with chmod +x and run with ./

It turns this:

├── Adella
├── adrianna
├── Barb
├── bebe
├── Carleen
├── catherina


├── A
│   ├── Adella
│   ├── adrianna
├── B
│   ├── Barb
│   └── bebe
├── C
    ├── Carleen
    ├── catherina

How it works

Let's break this down to see what everything does

  • for dir in */ ; do
  • This loops through the current directory and finds every item which ends with a / - that is, all directories


  • start=${dir:0:1}
  • Grab a sub-string from the directory name. In this case, the first character.



  • mv "$dir" ${start^^}
  • Move the directory we found into the newly created directory.


  • done
  • Finish the loop


  • Only works with folders - it won't move any files in your top level directory.
  • Non-ASCII characters are supported. For example, 你好 is sorted into .
  • Handles directories with spaces, punctuation, and numbers at the start.
  • No doubt there is some horrific bug lurking in those half-dozen lines. Be a friend and drop me a note in the comments, would you?

One thought on “Sort Folders Into Alphabetic Sub-Folders

  1. Andrew McGlashan says:

    More fun, let's see if this works:

    $ cat
    sort_assoc_array() {
    	for yr in ${years[@]}
    		echo $yr
    	done|sort -n
    declare -A years
    declare -a yrs file
    # collect files in top level directory to move
    files=( $(find . -maxdepth 1 -type f -name '20[01][0-9]*') )
    # work out which year folders are needed
    for filex in ${files[@]}
    	[ ! -z ${years[$dirx]} ] || {
    		echo add year $dirx
    # sort the years
    yrs=( $(sort_assoc_array) )
    # create the year folders
    for yr in ${yrs[@]}
    	[ -d "$yr" ] || mkdir "$yr/"
    	chown andrewm:andrewm "$yr/"
    # move the files to their /year/ folder
    for filex in ${files[@]}
    	mv "$filex" "$dirx/"
    # touch the year folder with the timestamp of the newest file for that year
    for yr in ${yrs[@]}
    	lastfileforyear=$(ls -rt ${yr}/|tail -1)
    	touch -r "$yr/$lastfileforyear" "$yr/"

Leave a Reply

Your email address will not be published. Required fields are marked *