File Move Based on 1st Character of File Name

I need some help with a unix script to mv image files to subdirectories based on the 1st character of the filename. See example below...

/images/main

1191.jpg
9999.jpg
A101.jpg
A102.jpg
B201.jpg
c333.jpg
...
Z999.jpg

I would like to move to the following:

/images/main/1/1191.jpg
/images/main/9/9999.jpg
/images/main/a/A101.jpg
/images/main/a/A102.jpg
/images/main/b/B201.jpg
/images/main/c/c333.jpg
...
/images/main/z/Z999.jpg

Any help would be greatly appreciated.

Thanks!

Another one:

#!/bin/sh

dir="/images/main"

for file in *.jpg
do
  sd="$dir"/`echo "$file"|cut -c 1`
  mkdir -p "$sd"
  mv "$file" "$sd"
done

Regards

franklin52 script is very good but needs a tweak to change the directory to lowercase.
tr "[A-Z]" "a-z"

BTW. Don't use this syntax because it is upset by single character filenames!
tr [A-Z] [a-z]

If you have a very large number of files (or the filenames contain space characters) the script will need some work to generate the list of files in a pipe without decending the directory tree. Depends on which unix and which version of "find" you have.

Worked great. Thanks for your help!

I know he already has his answer . . . but I see a lot of answers on here
that are overly complicated. The ksh itself has much of the functionality
of cut, awk and sed. For example:

# This creates a variable that is only 1 character-wide, left-justified,upper-case
typeset -u -L1 first_letter

cd images/main

/bin/ls *.jpg |
while read file ; do

first_letter=$file

mkdir $first_letter
/bin/mv $file $first_letter

done

This script has the added feature of being a single process.
Therefore, if it mattered, which it probably doesn't nowadays,
it would be the fastest way performance-wise to do this.

Worked great the 1st time, but now when I try add more files to the directory and re-run it just hangs. Is there an issue because the directory ($dir) has already been created? If so, how do I modify to check first to see if $dir exists?

You can run it like so:

ksh -xvf script_file 2>&1 | more

And see exactly where it's getting hung up.

Other answer to your question:

if [ ! -d $dir ]; then
mkdir $dir
fi

Thanks quirkasaurus!

It appears the original script worked the 1st time, but when I ran it again it created another subdirectory below the previous one. I tried running several times before I looked at the output and now I have a huge mess ...

/images/main/a/a/a/a/a/A101.jpg
/images/main/b/b/b/b/B201.jpg

Depending on where I killed the program there are a varying number of sub-directories.

How can I get back to everything in the /images/main directory and start all over again with an alternative suggestion?

Thanks for your patience on this thread and your help is greatly appreciated.

First, put everything back to normal:

mkdir /tmp/my_images

find images/main -name \*.jpg -exec /bin/cp {} /tmp/my_images \; -print

Verify that all the images are there:

ls /tmp/my_images

Nuke everything in images/main:

cd images/main

\rm -rf *

Put all the images back:

cp /tmp/my_images/* .

Now.

Don't use the solutions that used the find command.
Instead, use mine, posted earlier. This one will avoid
any recursive directory building problem.

HTH

HTH - Thank you! OK - Recovered!

I am now using your script. How do I modify to handle "Arguement List Too Long" error because I have 30,000 images in the directory?

typeset -u -L1 first_letter

/bin/ls |
grep '.jpg$' |
while read file ; do

first_letter=$file

mkdir $first_letter
/bin/mv $file $first_letter

done

With much help from quirkasaurus this problem was resolved using BASH script below:

#!/bin/sh

cd "$1"

/bin/ls |
grep '.jpg$' |
while read file ; do
  first_letter=`echo $file | cut -c 1 | tr '[A-Z]' '[a-z]'`
  mkdir -p $first_letter
  /bin/mv $file $first_letter
done