Wednesday, August 22, 2012

How to Flatten a Folder Structure in AppleScript

Introduction (i.e. The Problem)
You can skip this introduction if you already understand the problem and are trying to solve the same issue.  Just start at Describing the Solution.

Ok, so recently I was given a large archive of files.  These were old automated backups that I had nothing to do with in the past.  They were stored in individual directories.  The directories each had a name that indicated the date the backup was run.  Inside the directories were one or more files that indicated a time that the backup was started.  It looked a bit like this:

The above is much smaller than the actual directory but it gives you an idea.  There was a single top folder called "archive" that contained all the subdirectories (or folders.)  Each subdirectory had a date as the name in Year-Month-Day (yyyy-MM-dd) format separated by hyphens.  Under each directory was one or more files.  The files had names that indicated when their particular backup started in Hour-Minute-Second (HH-mm-ss) format separated by hyphens.

Now I had to run a batch application on every .bkp file to create a summary of each change for audit purposes.  This application could take an entire directory of .bkp files and generate the needed report.  It had one shortcoming though, it could take a single directory as its input and would look for every .bkp file but it was not recursive.  Meaning it would not check subdirectories.  That means I could manually point it to each "date" directory such as "02-03-2010" but not to the top level "archive" directory.  As there were over 500 "date" directories I really didn't want to have to do that manually.

Describing the Solution
What I needed was a way to move every .bkp file stored under a date directory up one level so the files were under the top level "archive" directory.  Then I could just point the batch application to the "archive" directory and it would run though every file.

However, in moving the files that only had the time as their name such as "11-00-00" out of its sub directory I would lose what date it was created on.  I'd rather not lose that information.

Even worse you can see several .bkp files have the same name so they could not all be moved into the top level directory without name conflicts.

What I needed was to prepend the subdirectory name such as "02-03-2010" to the .bkp filename so the filename was actually "02-03-2010_11-00-00.bkp" (in this case I used an underscore "_" character as a separator between the folder and the file name.)  Then I could move the file up to the top level directory and not worry about name conflicts or files being overwritten.

Searching the Web for a Solution
Since I'm on a Mac this seemed like a perfect job for AppleScript.  As a good engineer never reinvents the wheel I figured I'm not the first person to run into this problem so I could probably find a solution out there and just reuse it.

I found this first:  Flatten folder structure via AppleScript | Macworld
This script basically worked but it didn't solve the problem of duplicate named files being moved into the same directory.  I needed something a bit more advanced.

I also found this:  Mac OS X Hints
But that didn't seem to work and still didn't address the naming issues.

Unfortunately I didn't find any workable solutions.

Creating Our Own Solution
Ok, so here's the solution.  Looking at some of the code for the two links I listed above I wrote the following script.

-- Select the folder in the front most window that you want to flatten before running
-- this script deletes the folders it flattens so it can destroy data!
(* Behavior…

Select Folder_Top in the front most Finder window, then run script…

-Folder_Top (type: folder)
--A   (type: folder)
---1  (type: file)
---2  (type: file)
--B   (type: folder)
---1  (type: file)
---2  (type: file)

-Folder_Top (type: folder)
--A_1  (type: file)
--A_2  (type: file)
--B_1  (type: file)
--B_2  (type: file)


tell application "Finder"
set this_folder to (selection as alias)
set this_folder_list to every folder of this_folder
repeat with i in this_folder_list
set this_file_list to every file of i
repeat with x in this_file_list
set theFile to (name of x)
set theFolderName to name of container of x
set name of x to theFolderName & "_" & theFile -- change "_" to whatever seperater string you want.
end repeat
set this_file_list_with_new_name to every file of i
move this_file_list_with_new_name to this_folder
-- delete i  (* uncomment this line to delete the subdirectories when done*)
end repeat
end tell

You should be able to copy and past this into the AppleScript Editor.  Then go into the Finder and select your top level folder.  Go back to the Script Editor and click Run.  If you trust the script uncomment the delete line and it will remove the empty subdirectories when it is done moving the files.  Good luck!

I've received a couple of emails that this can be useful in preparing to batch process videos with Handbrake if you don't want to use the Handbrake CLI (Command Line Interface.)  I added a mention here so if anyone searches specifically on Handbrake folders in Mac OS X they will find this entry.

I was not able to figure out how to do this using the more simple Automator in Mac OS X.  I realize you can use Automator to call an AppleScript but that defeats the point here.  If anyone can implement this logic using Automator I'd love to hear from you.


Unknown said...

Thanks you. I've needed a solution for this problem for ages and yours worked perfectly. I was about to open up applescript and try to write it myself when I found your script. It works well, however it's very very slow.

Lily Charlie said...

The best part of software for folder locking is that it is easy to use. You don't need any kind of technical expertise to use the software. Folder lock

Kevin Dellinger said...

Thanks very interesting blog! click for more info Five Lessons About Encryption Software You Need To Learn Before You Hit 40 & Five Ways To How To Encrypt A Password For Free In 60 Minutes

Anonymous said...

This is a fantastic website and I can not recommend you guys enough. Fire resistant cloth

Anonymous said...

I don’t think many of websites provide this type of information. orthopedic surgeon salary 2018

jenifferleio12 said...

Pleasant stuff! I like to peruse the data that you have imparted to us. I need to get more updates to expand my insight.

alexathomson said...

There may be many technical issues but the only single solution. Brother Printer Support Service is one stop solution for Brother Printer. This helps users to protect the functionality of Brother Printers.

Eva winget said...

Thank you for sharing such informative and great stuff please keep sharingquickbooks support

Eva winget said...
This comment has been removed by the author.
Eva winget said...

very enthutheastic and amazing post i really liked it please post more in future please keep sharing. brother printer support

Brother Printer Support said...

Epson Printers including wireless, inkjet and laser jet which require professional help to identify the issues and delivers the best solution according to the requirements. The Epson Printer support service is performed by certified technicians to offer quality service at affordable charges.

PrinterCustomerService said...

Facing a malfunction with your TurboTax software could cause hindrance in your office activities. To minimize your losses and resource allocation, reach our turbotax customer service team and get help from our experts. They will help you out with any error or glitch that you may be encountering.

Printer Support said...

Lexmark provides an excellent range of printers and is one of the leading brand across the globe. For any issue related to Lexmark printer, call our lexmark printer support number today. Our technical experts provide an excellent Lexmark printer technical support at a very reasonable price.