Bash Script to Sort Files into Alphabetical Folders on ReadyNAS Duo v1

bashfilesscripting

I have an old ReadyNAS Duo v1 (Sparc) running an unknown flavour of Linux.

I have a folder structure with 1,000+ files I want to move into a folder structure based on the first letter of the file name (case insensitive).

Ideally I'd like the file structure to look like this:

myfiles-+
        +-A
          + Apple.txt
          + avocado.txt
        +-B
          + Banana.txt
          + broccoli.txt
etc. etc.

I've had a Google but have only found GUI tools.

Can this be done via the command line or a script?

Best Answer

Here's a bit of a one liner that will do what you want:

$ mkdir -p output/{A..Z}; for i in tstdir/*; do export FILE=$(basename "$i");  LTR=$(echo" ${FILE:0:1}" | tr [a-z] [A-Z]); mv "$i" "output/$LTR/$FILE" ; done

Here's the same command in expanded form so you can see what's going on:

$ mkdir -p output/{A..Z}
$ for i in tstdir/*; do 
    FILE=$(basename "$i")  
    LTR=$(echo "${FILE:0:1}" | tr [a-z] [A-Z])
    mv "$i" "output/$LTR/$FILE"
  done

Details

The above first assumes that the output directory of just the letters doesn't exist and so will create it,

$ mkdir -p output/{A..Z}

The for loop works as follows, looping through all the files in tstdir/*. It then determines the basename of this path, and stores it in the variable, $FILE. Each iteration through the loop is stored in the variable $i.

FILE=$(basename "$i")

We then use Bashes ability to return the 1st character of the named variable, $FILE, and then use tr to convert any lowercase characters to uppers.

LTR=$(echo "${FILE:0:1}" | tr [a-z] [A-Z])

Breaking this down a bit more:

$ echo "${FILE:0:1}"
s
$ echo "${FILE:0:1}"
T

With the tr code you can now see what's going on:

$ echo "${FILE:0:1}" | tr [a-z] [A-Z]
S
$ echo "${FILE:0:1}" | tr [a-z] [A-Z]
T

The rest of the command just moves the files into their corresponding first letter directory.

Example

Say we have this directory of files:

$ touch {a-z}file {A-Z}file

$ tree tstdir/ | head -10
tstdir/
|-- afile
|-- Afile
|-- bfile
|-- Bfile
|-- cfile
|-- Cfile
|-- dfile
|-- Dfile
|-- efile
...

After running the one liner:

$ tree output/ | head -10
output/
|-- A
|   |-- afile
|   `-- Afile
|-- B
|   |-- bfile
|   `-- Bfile
|-- C
|   |-- cfile
|   `-- Cfile
...
Related Question