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?

One thought on “Sort Folders Into Alphabetic Sub-Folders

  1. 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
    

Leave a Reply

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

%d bloggers like this: