How to create new folders for files that contain the same text/characters?

Just wanted to apologise fist as I have ZERO KNOWLEDGE on this.

I’ve been exploring the Automator app and it seems like it won’t help me that much as I also need to to type in each texts manually.
I wanted an automation to sort my files by creating folders for the files containing the same text/characters.

Sample files:

  • IMG_0001.jpg
  • IMG_0002.jpg
  • IMG_0003.jpg
  • PIC_0001.jpg
  • PIC_0002.jpg
  • PIC_0003.jpg
  • PHO_0001.jpg
  • PHO_0002.jpg
  • PHO_0003.jpg

Output I want through automation

  • IMG FOLDER
    • IMG_0001.jpg
    • IMG_0002.jpg
    • IMG_0003.jpg
  • PIC FOLDER
    • PIC_0001.jpg
    • PIC_0002.jpg
    • PIC_0003.jpg
  • PHO FOLDER
    • PHO_0001.jpg
    • PHO_0002.jpg
    • PHO_0003.jpg

I have hundreds of these to sort and It’s taking me time to do this manually.
I have the list of texts (IMG, PIC, PHO, etc.) that I need to sort in a spreadsheet.

Hope you could help.

Thanks!

A few questions…

  • Are all of the resulting folders going to end up in the same place?
  • How many files/folders are there — approximately?
  • Does the spreadsheet have one column that contains the entire path of every file? What does an example entry look like?
  • What happens if two files are kept in different folders but have the same name?

Here are several other questions…

Where are the sample files? in one folder, or in multiple folders in multiple locations?

Where do you want the new folder to be created? In a predetermined location, or the same location as the input files (provided they are all in one folder to begin with), or in a location that the user chooses each time the script is run?

Your original question has many vagueries you didn’t provide for.

Hi! I appreciate you checking on this!

All the images that needs to be sorted are all in 1 folder. There’s no subfolders.
Would prefer it to be in the same location.

Thank you!

This is a simple script which first asks for a base folder.
Then it gets the file names in this folder and checks if the names end with jpg and if the fourth character is an underscore.

On success the three letter subfolder is being created (if it doesn’t exist yet) and the image is moved to that folder

set baseFolder to POSIX path of (choose folder with prompt "Choose the image folder")
set theImages to list folder baseFolder without invisibles
repeat with anImage in theImages
	if anImage ends with "jpg" and (get offset of "_" in anImage) is 4 then
		set destinationFolder to baseFolder & text 1 thru 3 of anImage & "/"
		do shell script "/bin/mkdir -p " & quoted form of destinationFolder
		do shell script "mv " & quoted form of (baseFolder & anImage) & space & quoted form of (destinationFolder & anImage)
	end if
end repeat

Also, why is it taking you a long time manually?

Just view the folder as list, sorted by name. All the IMG files will be next to each other. So will the PIC and PHO files. select each group and move to their respective folders. 20 seconds max.

Here is my script that doesn’t use “do shell script”…

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

property extList : {"IMG", "PIC", "PHO"}

local myFolder, myFiles, anItem, ext

set myFolder to choose folder with prompt "Select folder that contains images to sort…"
set myFolder to myFolder as text

repeat with anItem in extList
	try
		alias (myFolder & anItem)
	on error
		tell application "System Events"
			make new folder at folder myFolder with properties {name:anItem}
		end tell
	end try
end repeat
tell application "System Events"
	set myFiles to files of folder myFolder
	repeat with anItem in myFiles
		set anItem to contents of anItem
		if (name extension of anItem) = "jpg" then
			repeat with ext in extList
				if name of anItem begins with ext then
					move anItem to folder (myFolder & ext)
					exit repeat
				end if
			end repeat
		end if
	end repeat
end tell

It should be faster on large number of files. I haven’t tested tho.

Here is a slightly better version with fewer repeat loops…

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

property extList : {"IMG", "PIC", "PHO"}

local myFolder, myFiles, anItem, ext

set myFolder to choose folder with prompt "Select folder that contains images to sort…"
set myFolder to myFolder as text

repeat with anItem in extList
	try
		alias (myFolder & anItem)
	on error
		tell application "System Events"
			make new folder at folder myFolder with properties {name:anItem}
		end tell
	end try
end repeat
tell application "System Events"
	set myFiles to files of folder myFolder
	repeat with anItem in myFiles
		set anItem to contents of anItem
		if (name extension of anItem) = "jpg" then
			set ext to name of anItem
			set ext to text 1 thru 3 of ext
			if ext is in extList then move anItem to folder (myFolder & ext)
		end if
	end repeat
end tell

This is a very odd decision to use the resolution of an alias reference as a test to determine whether or not a folder exists, given that every single other line in the script relies on calling out to System Events, which provides a means to test for the existence of filesystem paths (namely, the exists command) that is going to be faster than trying to resolve an alias.

That said, you dont actually need to test for existence, as System Events’s make command doesn’t complain if the path already exists, provided that it points to the same type of object that the command is being asked to create. So you can essentially get away with simply doing this:

repeat with anItem in extList
		tell application "System Events"
			make new folder at folder myFolder with properties {name:anItem}
end repeat

But, the truly robust approach would involve testing for existence, just in case there happens to be something at the path <myFolder>/<anItem> that turned out not to be a folder:

repeat with anItem in extList
		tell application "System Events"
			tell folder myFolder to if not (item anItem exists) then
				make new folder with properties {name:anItem}
			end if
		end tell
end repeat

I use “alias” instead of “exists” because “alias” is actually between 2.5 and 20 times faster.

Every AppleScript call to another application is at least one magnitude slower than using a native call.

Yes and no. It’s not the case that your “native call” saves you from having to call out to some other application (ie. System Events). Your entire script invokes System Events, save for this one decision to go “native”. Therefore, you’re not really saving any time at all.

That’s not a very meaningful statement on its own. For one, a result that varies by up to 25% immediately tells you it’s not reliable.

But I’m not contesting the idea that alias resolution can and often will be faster than calling out to System Events, where these two things are happening in a vacuum. I’m suggesting that your script is calling out to System Events anyway, so it seems like a peculiar decision to make this one exception, citing execution speed as the reason, and then implementing the method in a sub-optimal manner.

For instance, coercing to an alias (...as alias) is no slower than using alias aa an object specifier when the path resolves, but fails far sooner when the path doesn’t. Then, in the cases of failure, throwing and catching an exception takes more time than providing an alternative class to allow coercion to take place and using this to indicate that alias resolution failed.

There’s also the issue that simply testing the resolution of an alias isn’t sufficient to determine that what it points to is a folder, however this is an easy solve.

There’s no right or wrong way to do any of this, and we all have our own individual preferences and stylistic choices. If nothing I’ve written is new to you, then hopefully it might be something new for others to contemplate on and experiment with. Onwards and upwards, as they say.