Automatically create and sort into subfolders

Hi,


I have a large folder directory with a lot of photos in them.


Basically something like


  • Clouds
    • Cloud_01
    • Cloud_02
    • etc.
  • Trees
    • Tree_01
    • Tree_02


Each subfolder has both .jpg and .cr2 (raw) files in them


I'd like to be able to run a script or automator sequence which will automaticall look inside these folders, and then create folders RAW and JPG and then put the corresponding files into the correct folder based on the filetype. So I'll wind up with something like this:


Clouds

  • Cloud_01
    • JPG
      • All JPG files
    • RAW
      • All RAW files
  • Cloud_02
    • JPG
    • RAW
  • etc.

MacBook Pro with Retina display, OS X Mavericks (10.9.1)

Posted on Jan 27, 2014 7:45 AM

Reply
6 replies

Jan 27, 2014 11:02 AM in response to DrPepperShaker

Maybe something like this:



set theMainFolder to choose folder


tell application "Finder"

set theFolders to folders of theMainFolder

repeat with thisFolder in theFolders

set theSubFolders to folders of thisFolder

repeat with thisSubFolder in theSubFolders

if not (exists (folder "JPG" of thisSubFolder)) then

make new folder at thisSubFolder with properties {name:"JPG"}

end if

if not (exists (folder "RAW" of thisSubFolder)) then

make new folder at thisSubFolder with properties {name:"RAW"}

end if

move (files of thisSubFolder whose name extension is "jpg") ¬

to folder "JPG" of thisSubFolder with replacing

move (files of thisSubFolder whose name extension is "cr2") ¬

to folder "RAW" of thisSubFolder with replacing

end repeat

end repeat

end tell

Jan 27, 2014 11:38 AM in response to DrPepperShaker

Hello


You may try something like this shell script.


#!/bin/bash

d=~/desktop/test    # start directory

while read -d $'\0' f
do
    name=${f##*/}
    path=${f/%$name/}
    dir="${path}JPG"
    [[ -d $dir ]] || mkdir -p "$dir"
    mv "$f" "$dir/$name"
done < <(find "$d" -type f -iname '*.jpg' -print0)

while read -d $'\0' f
do
    name=${f##*/}
    path=${f/%$name/}
    dir="${path}RAW"
    [[ -d $dir ]] || mkdir -p "$dir"
    mv "$f" "$dir/$name"
done < <(find "$d" -type f -iname '*.cr2' -print0)
exit 0



An AppleScript wrapper would be:


set d to (choose folder)'s POSIX path
if d ends with "/" then set d to d's text 1 thru -2

do shell script "/bin/bash -s <<'EOF' -- " & d's quoted form & "
d=\"$1\"

while read -d $'\\0' f
do
    name=${f##*/}
    path=${f/%$name/}
    dir=\"${path}JPG\"
    [[ -d $dir ]] || mkdir -p \"$dir\"
    mv \"$f\" \"$dir/$name\"
done < <(find \"$d\" -type f -iname '*.jpg' -print0)

while read -d $'\\0' f
do
    name=${f##*/}
    path=${f/%$name/}
    dir=\"${path}RAW\"
    [[ -d $dir ]] || mkdir -p \"$dir\"
    mv \"$f\" \"$dir/$name\"
done < <(find \"$d\" -type f -iname '*.cr2' -print0)
exit 0
EOF"



You may also create an Automator workflow with actions as follows:


1) Ask for Finder Items

Type = Folders

Allow Multiple Selection = false


2) Run Shell Script

Shell = /bin/bash

Pass input = as argument

contents =


#!/bin/bash

d="$1"

while read -d $'\0' f
do
    name=${f##*/}
    path=${f/%$name/}
    dir="${path}JPG"
    [[ -d $dir ]] || mkdir -p "$dir"
    mv "$f" "$dir/$name"
done < <(find "$d" -type f -iname '*.jpg' -print0)

while read -d $'\0' f
do
    name=${f##*/}
    path=${f/%$name/}
    dir="${path}RAW"
    [[ -d $dir ]] || mkdir -p "$dir"
    mv "$f" "$dir/$name"
done < <(find "$d" -type f -iname '*.cr2' -print0)
exit 0


Resulting workflow will look like this:


User uploaded file



Hope this may help,

H

Jan 27, 2014 1:19 PM in response to DrPepperShaker

Hello


Here's revised version which will ignore *.jpg or *.cr2 files already sorted in JPG or RAW folders respectively. This will keep the script from sorting files into nested JPG/JPG/... or RAW/RAW/... directories when it is by any chance applied to already processed directories.


#!/bin/bash

d=~/desktop/test    # start directory

while read -d $'\0' f
do
    name=${f##*/}
    path=${f/%$name/}
    [[ $path =~ .*/JPG/ ]] && continue    # do nothing if already sorted
    dir="${path}JPG"
    [[ -d $dir ]] || mkdir -p "$dir"
    mv "$f" "$dir/$name"
done < <(find "$d" -type f -iname '*.jpg' -print0)

while read -d $'\0' f
do
    name=${f##*/}
    path=${f/%$name/}
    [[ $path =~ .*/RAW/ ]] && continue    # do nothing if already sorted
    dir="${path}RAW"
    [[ -d $dir ]] || mkdir -p "$dir"
    mv "$f" "$dir/$name"
done < <(find "$d" -type f -iname '*.cr2' -print0)
exit 0


AppleScript wrapper is:


set d to (choose folder)'s POSIX path
if d ends with "/" then set d to d's text 1 thru -2

do shell script "/bin/bash -s <<'EOF' -- " & d's quoted form & "
d=\"$1\"

while read -d $'\\0' f
do
    name=${f##*/}
    path=${f/%$name/}
    [[ $path =~ .*/JPG/ ]] && continue    # do nothing if already sorted
    dir=\"${path}JPG\"
    [[ -d $dir ]] || mkdir -p \"$dir\"
    mv \"$f\" \"$dir/$name\"
done < <(find \"$d\" -type f -iname '*.jpg' -print0)

while read -d $'\\0' f
do
    name=${f##*/}
    path=${f/%$name/}
    [[ $path =~ .*/RAW/ ]] && continue    # do nothing if already sorted
    dir=\"${path}RAW\"
    [[ -d $dir ]] || mkdir -p \"$dir\"
    mv \"$f\" \"$dir/$name\"
done < <(find \"$d\" -type f -iname '*.cr2' -print0)
exit 0
EOF"


Automator workflow is omitted.


Regards,

H

Jan 27, 2014 2:10 PM in response to DrPepperShaker

And Ruby to the rescue too.


This does what you want and extends image handling to other formats as well. I have tested it both in the Terminal and as an Automator application. It does not currently support multiple folder selection.


The Automator workflow:


User uploaded file

and the ruby code that goes in the Run Shell Script workflow window:


#!/usr/bin/ruby
# content: UTF-8
# Usage: program.rb folder
# Author: VikingOSX, 01/14, Apple Support Community


require 'find'
require 'fileutils'


init_folder, parent_folder, fextension, newfile = String.new
pathnfo, filenfo = Array.new
# pattern to filter on filename extensions
filetype_regex = /[^\/:]+\.(?i:jpeg|jpg|cr2|png|gif|svg)/


# Argument passed and forced to string
init_folder = ARGV.join("")


# get the full path to folder passed as argument
parent_folder = File.realdirpath(init_folder)


# Walk down directory hierarchy as main loop
Find.find(parent_folder) do |xfile|
    if File.directory?(xfile)
        # keep the current full path and directory/file name in an array
        pathnfo  = File.split(xfile)
        next
    else
        # Either there is a filename match with returned image extension as string
        # or a nil is returned
        imagename = filetype_regex.match(xfile).to_s unless xfile.include? ".DS_Store"


        if imagename == nil
            next
        end


        filenfo = File.split(xfile)
        extension = File.extname(imagename)


        #make folder from current base image name
        xfiledir = File.join(pathnfo.first, pathnfo.last, File.basename(xfile, extension))
        FileUtils.mkdir_p(xfiledir) unless File.directory?(xfiledir)


        # make an image type sub-folder and move respective file to it.
        case extension.downcase
        when ".jpg", ".jpeg"
            jpgfolder = File.join(xfiledir, "JPG")
            FileUtils.mkdir_p jpgfolder unless File.directory?(jpgfolder)
            xfilejpg = File.join(jpgfolder, filenfo.last)
            FileUtils.mv(xfile, xfilejpg)
            next
        when ".cr2"
            rawfolder = File.join(xfiledir, "RAW")
            FileUtils.mkdir_p rawfolder unless File.directory?(rawfolder)
            xfileraw = File.join(rawfolder, filenfo.last)
            FileUtils.mv(xfile, xfileraw)
            next
        when ".png"
            pngfolder = File.join(xfiledir, "PNG")
            FileUtils.mkdir_p pngfolder unless File.directory?(pngfolder)
            xfilepng = File.join(pngfolder, filenfo.last)
            FileUtils.mv(xfile, xfilepng)
            next
        when ".gif"
            giffolder = File.join(xfiledir, "GIF")
            FileUtils.mkdir_p giffolder unless File.directory?(giffolder)
            xfilegif = File.join(giffolder, filenfo.last)
            FileUtils.mv(xfile, xfilegif)
            next
        when ".svg"
            svgfolder = File.join(xfiledir, "SVG")
            FileUtils.mkdir_p svgfolder unless File.directory?(svgfolder)
            xfilesvg = File.join(svgfolder, filenfo.last)
            FileUtils.mv(xfile, xfilesvg)
            next
        else
            puts "Something poignantly went wrong"
            next
        end
    end
end

Jan 28, 2014 4:31 AM in response to Hiroto

Oops. Previous scripts contain problematic code to get path of file.


The statement:


    path=${f/%$name/}


should have been:


    path=${f/%"$name"/}


or more simply:


    path=${f%"$name"}


because the original statement can return wrong result if $name contains pattern meta characters, such as [ ] * ?.


Here's the corrected scripts. Sorry for any confusions I may have made.


#!/bin/bash

d=~/desktop/test    # start directory

while read -d $'\0' f
do
    name=${f##*/}
    path=${f/%"$name"/}
    [[ $path =~ .*/JPG/ ]] && continue    # do nothing if already sorted
    dir="${path}JPG"
    [[ -d $dir ]] || mkdir -p "$dir"
    mv "$f" "$dir/$name"
done < <(find "$d" -type f -iname '*.jpg' -print0)

while read -d $'\0' f
do
    name=${f##*/}
    path=${f/%"$name"/}
    [[ $path =~ .*/RAW/ ]] && continue    # do nothing if already sorted
    dir="${path}RAW"
    [[ -d $dir ]] || mkdir -p "$dir"
    mv "$f" "$dir/$name"
done < <(find "$d" -type f -iname '*.cr2' -print0)
exit 0


AppleScript wrapper is:


set d to (choose folder)'s POSIX path
if d ends with "/" then set d to d's text 1 thru -2

do shell script "/bin/bash -s <<'EOF' -- " & d's quoted form & "
d=\"$1\"

while read -d $'\\0' f
do
    name=${f##*/}
    path=${f/%\"$name\"/}
    [[ $path =~ .*/JPG/ ]] && continue    # do nothing if already sorted
    dir=\"${path}JPG\"
    [[ -d $dir ]] || mkdir -p \"$dir\"
    mv \"$f\" \"$dir/$name\"
done < <(find \"$d\" -type f -iname '*.jpg' -print0)

while read -d $'\\0' f
do
    name=${f##*/}
    path=${f/%\"$name\"/}
    [[ $path =~ .*/RAW/ ]] && continue    # do nothing if already sorted
    dir=\"${path}RAW\"
    [[ -d $dir ]] || mkdir -p \"$dir\"
    mv \"$f\" \"$dir/$name\"
done < <(find \"$d\" -type f -iname '*.cr2' -print0)
exit 0
EOF"

Jan 28, 2014 5:31 AM in response to VikingOSX

Here is a refactored (and tested) version of the Ruby code from my previous post.



#!/usr/bin/ruby
# content: UTF-8
# Usage: program.rb folder
# Author: VikingOSX, 01/14, Apple Support Community


require 'find'
require 'fileutils'


init_folder, parent_folder, fextension, newfile = String.new
pathnfo, filenfo = Array.new
# pattern to filter supported image types
filetype_regex = /[^\/:]+\.(?i:jpeg|jpg|cr2|png|gif|svg)/


# Argument passed and forced to string
init_folder = ARGV.join("")


# get the full path to folder passed as argument
parent_folder = File.realdirpath(init_folder)


# Walk down directory hierarchy as main loop
Find.find(parent_folder) do |xfile|
    if File.directory?(xfile)
        # keep the current full path and directory/file name in an array
        pathnfo  = File.split(xfile)
        next
    else
        # Return filename if supported image type, otherwise nil
        imagename = filetype_regex.match(xfile).to_s unless xfile.include? ".DS_Store"


        if imagename == nil
            next
        end


        filenfo = File.split(xfile)
        extension = File.extname(imagename)


        #make folder from current base image name
        xfiledir = File.join(pathnfo.first, pathnfo.last, File.basename(xfile, extension))
        FileUtils.mkdir_p(xfiledir) unless File.directory?(xfiledir)


        # make an image type sub-folder and move respective file to it.
        case extension.downcase
        when ".jpg", ".jpeg"
            imgfolder = File.join(xfiledir, "JPG")
        when ".cr2"
            imgfolder = File.join(xfiledir, "RAW")
        when ".png"
            imgfolder = File.join(xfiledir, "PNG")
        when ".gif"
            imgfolder = File.join(xfiledir, "GIF")
        when ".svg"
            imgfolder = File.join(xfiledir, "SVG")
        else
            printf("Unsupported File Format: %s\n", xfile)
            next
        end
        # Make image kind folder, new file path to it, and move current file
        FileUtils.mkdir_p imgfolder unless File.directory?(imgfolder)
        imgpath = File.join(imgfolder, filenfo.last)
        FileUtils.mv(xfile, imgpath)
        next
    end
end

This thread has been closed by the system or the community team. You may vote for any posts you find helpful, or search the Community for additional answers.

Automatically create and sort into subfolders

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple Account.