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.

#!/bin/bash
for dir in */ ; do
    start=${dir:0:1}
    mkdir -p ${start^^}
    mv "$dir" ${start^^}
done

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

It turns this:

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

Into:

.
├── 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

Warnings

  • 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?

Share this post on…

  • Mastodon
  • Facebook
  • LinkedIn
  • BlueSky
  • Threads
  • Reddit
  • HackerNews
  • Lobsters
  • WhatsApp
  • Telegram

One thought on “Sort Folders Into Alphabetic Sub-Folders”

  1. Andrew McGlashan says:

    More fun, let's see if this works:

    $ cat organize_files.sh
    #!/bin/bash
    
    sort_assoc_array() {
        for yr in ${years[@]}
        do
    	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[@]}
    do
        dirx=${filex:2:4}
        [ ! -z ${years[$dirx]} ] || {
    	echo add year $dirx
    	years[$dirx]=$dirx
        }
    done
    
    # sort the years
    yrs=( $(sort_assoc_array) )
    
    # create the year folders
    for yr in ${yrs[@]}
    do
        [ -d "$yr" ] || mkdir "$yr/"
        chown andrewm:andrewm "$yr/"
    done
    
    # move the files to their /year/ folder
    for filex in ${files[@]}
    do
        dirx=${filex:2:4}
        mv "$filex" "$dirx/"
    done
    
    # touch the year folder with the timestamp of the newest file for that year
    for yr in ${yrs[@]}
    do
        lastfileforyear=$(ls -rt ${yr}/|tail -1)
        touch -r "$yr/$lastfileforyear" "$yr/"
    done
    
    Reply

What are your reckons?

All comments are moderated and may not be published immediately. Your email address will not be published.

Allowed HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <p> <pre> <br> <img src="" alt="" title="" srcset="">