Sorting image sequences into subfolders

I do quite a bit of 3D animations, and the render results are a mess of image files, thousands of them. They emerge maddeningly unsorted, and the app I use to composite them (After Effects) doesn’t sort them into their ‘passes’ like it should. Thus it can take an hour to get files into AE to begin work on them. But AE will import properly if the images are sorted into subfolders.

I’d like to know whether a script exists that looks at a folder of files and sorts it into subfolders by simple search criteria. For example, the image look sequences like this


filename_specular_001.tga
filename_specular_002.tga
filename_specular_003.tga
.
.
.
filename_specular_999.tga



filename_refl_001.tga
filename_refl_002.tga
filename_refl_003.tga
.
.
.
filename_refl_999.tga


(etc.)

In this case, the ‘specular’ and the ‘refl’ are the things I’d like to use to sort these image sequences into folders. Those never change. The best result would be a script that created a series of folders with the names below and sorted image files into them:

Subfolders

rgb
reflection
motion
normal
shadow
specular
object_1
object_2
object_3
object_4
object_5
post_1

Does this exist? Or can this be made?

This is one way to do it… just fill in the rest of the values pairs in the list

-- format is {"folder name","search string"}
set theSubFolders to {¬
	{"specular", "specular"}, ¬
	{"refelction", "refl"} ¬
		}

set source to (choose folder with prompt "Please select the source images folder.") as Unicode text
set destination to (choose folder with prompt "Sort images to which base folder?") as Unicode text

tell application "Finder"
	repeat with aFolder in theSubFolders
		try
			(destination & (item 1 of aFolder)) as alias
		on error
			make new folder at folder destination with properties {name:(item 1 of aFolder)}
		end try
		move (every file of entire contents of folder source whose name contains (item 2 of aFolder)) to folder (destination & (item 1 of aFolder))
	end repeat
end tell

Hi, Govinda.

It looks as though your folder could contain thousands of files, in which case shell scripting might be the way to go:

-- Choose a source folder.
set sourceFldr to quoted form of POSIX path of (choose folder with prompt " Please select a source folder.")
-- List its item names to a temporary file in the folder.
set tempFile to sourceFldr & "temp.txt"
do shell script ("ls " & sourceFldr & " > " & tempFile)
-- Create the subfolders in the folder.
do shell script ("mkdir -p " & sourceFldr & "{rgb,refl,motion,normal,shadow,specular,object_{1,2,3,4,5},post_1}")

set subfolderNames to {"rgb", "refl", "motion", "normal", "shadow", "specular", "object_1", "object_2", "object_3", "object_4", "object_5", "post_1"}
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to "," as Unicode text
-- Cycle through the subfolder names.
repeat with thisFolderName in subfolderNames
	try
		-- Make a textual braced list of all the item names in the folder that contain this subfolder name.
		set nList to "{" & paragraphs of (do shell script "grep _" & thisFolderName & "_ " & tempFile) & "}"
		-- Us it in a shell script to move the matching files into that subfolder.
		do shell script ("mv " & sourceFldr & nList & " " & sourceFldr & thisFolderName)
	end try
end repeat
set AppleScript's text item delimiters to astid
-- Delete the temporary file.
do shell script ("rm " & tempFile)

This works well, but I’m not very well up on Unix methods. Someone more knowledgeable might be able to suggest some Unix text manipulation that will link the two do shell script calls in the repeat into a single call.

we should be able to get away with doing a simple find with xargs

set sourceFldr to POSIX path of (choose folder with prompt " Please select a source folder.")
-- Create the subfolders in the folder.
do shell script ("mkdir -p " & quoted form of sourceFldr & "{rgb,refl,motion,normal,shadow,specular,object_{1,2,3,4,5},post_1}")

set subfolderNames to {"rgb", "refl", "motion", "normal", "shadow", "specular", "object_1", "object_2", "object_3", "object_4", "object_5", "post_1"}

repeat with thisFolderName in subfolderNames
	do shell script "find " & quoted form of sourceFldr & " -name \"*_" & thisFolderName & "_*\" -maxdepth 1 -print0 | xargs -0 -J {} mv {} " & quoted form of (sourceFldr & thisFolderName)
end repeat

Or for giggles lets do it all using only one shell call (exec rather than xargs)

set sourceFldr to POSIX path of (choose folder with prompt " Please select a source folder.")
-- Create the subfolders in the folder.
set theCommand to ("mkdir -p " & quoted form of sourceFldr & "{rgb,refl,motion,normal,shadow,specular,object_{1,2,3,4,5},post_1};")

set subfolderNames to {"rgb", "refl", "motion", "normal", "shadow", "specular", "object_1", "object_2", "object_3", "object_4", "object_5", "post_1"}

repeat with thisFolderName in subfolderNames
	set theCommand to theCommand & "find " & quoted form of sourceFldr & " -name \"*_" & thisFolderName & "_*\" -maxdepth 1 -exec mv {} " & quoted form of (sourceFldr & thisFolderName) & " \\;;"
end repeat

do shell script theCommand

I would like to point out that I would recommend the xargs version rather then the -exec for a large amount of files.

::Edit:: Added in the maxdepth so we dont transverse into subfolders that may have been preexisting and pointlessly move files.

You know, the first version of this worked like a dream, but it did beach-ball/lock Finder me for a few minutes on my 4,000-file test, and if I ran an app during that time, I experienced my first kernel panic in months. I put that off to me being too fidgety, and I was fully set to put it in my workflow as it saves a TON of time. Thanks so much.

What is the difference between using the first version and a shell script?

Self-reply, I see the difference. It runs like Allen Iverson on a fast break (edit: referring to James’s ‘for giggles’ script). I just phoned a colleague he’s equally excited. I see that it creates the subfolders in the same folder, which is just fine by the way.

It missed a few file names, probably from the syntax? Note the trailing underscore between the term ‘object_1’ and the frame number ‘0000.’ The sequences with the trailing underscore sorted; those without didn’t. Adding a ‘0’ after this portion:

set theCommand to ("mkdir -p " & quoted form of sourceFldr & "{rgb0,refl0,motion0,normal0,shadow0,specular0,object_{1,2,3,4,5},post_1};")

…didn’t solve it, which surprised me because I thought for a second I was all clever.

To wit, it caught this file sequence and sorted it into a folder:
fp_03_v03_object_1_0000.jpg
.
.
.
fp_03_v03_object_1_0340.jpg

But it didn’t catch this file sequence to sort into a folder (note lack of underscore between ‘motion’ and the frame number):
fp_03_v03_motion0000.jpg
.
.
.
fp_03_v03_motion0340.jpg

Hi, Govinda.

I didn’t realise that the “folder name” in the file names wouldn’t always be followed by an underscore. My script looks for items whose names contain the folder name with an underscore at each end. This is just to ensure that the folder itself isn’t turned up in the search. (I don’t know if this is necessary.) James’s shell scripts are developed from that.

It should be enough just to include the leading underscore in the name search. So where the scripts say _ " & thisFolderName & "_, just cut the second underscore.

set sourceFldr to POSIX path of (choose folder with prompt " Please select a source folder.")
-- Create the subfolders in the folder.
do shell script ("mkdir -p " & quoted form of sourceFldr & "{rgb,refl,motion,normal,shadow,specular,object_{1,2,3,4,5},post_1}")

set subfolderNames to {"rgb", "refl", "motion", "normal", "shadow", "specular", "object_1", "object_2", "object_3", "object_4", "object_5", "post_1"}

repeat with thisFolderName in subfolderNames
	do shell script "find " & quoted form of sourceFldr & " -name \"*_" & thisFolderName & "*\" -maxdepth 1 -print0 | xargs -0 -J {} mv {} " & quoted form of (sourceFldr & thisFolderName)
end repeat

James’s xargs script errors on the Jaguar machine I’m using at the moment, so I can’t test it; but I expect that when I try it in Tiger, it’ll turn out to be the fastest of the three shell script approaches. The exec one is indeed quite slow!

we could modify the find statement as well to only allow items whose type is file

	do shell script "find " & quoted form of sourceFldr & " -type f -name \"*" & thisFolderName & "*\" -maxdepth 1 -print0 | xargs -0 -J {} mv {} " & quoted form of (sourceFldr & thisFolderName)

Exec is indeed slow! That was pretty much just an exercise in one-linerness LOL

Exec can be speed up with a ‘+’ so it acts much like xargs, but I don’t believe it can be invoked properly with the particular utility structure we are calling. So yeah xargs is the way to go =)

We have liftoff!

Guys, send me a PM with PayPal links. This saves me and a lot of other people too much time on paying jobs to be a freely provided script. :slight_smile:

Govinda - when I’m preparing frame sequences for compositing I find A Better Finder Rename to be an invaluable tool. It does rapid bulk renaming of files & folders and lets you do all kinds of clever text manipulation in the filenames. It’s WAY smarter than the bulk rename function in Bridge.

If you’re not using it already, check it out:

http://www.publicspace.net/ABetterFinderRename/

I meant to reply days ago but things got crazy. So far so good with this script. I’ve shared it with a few people who probably won’t use it for a few months, but they have this forum’s address for reference.

About A Better Finder, I do own that and absolutely love it. In fact, when there was a bit of a glitch in one of the early versions of this script, it wasn’t that big a deal because A Better Finder Renamer was going to allow me to add in underscores quite easily. It’s a million times better than the built-in scripts for renaming batches of files.

Cheers and thanks again!