I have a script that deletes files older then a certain number of days. The meat of the script is the following loop:
set retention to 7 * days
set cut_off to (current date) - retention
tell application "Finder"
set file_list to items of folder pdf_folder
repeat with t_item in file_list
set file_info to info for alias (t_item as text)
set created to creation date of the file_info
if (created < cut_off) then
move alias (t_item as text) to trash
end if
end repeat
empty trash
end tell
While the script works fine, it is agonizingly slow. It has to scan more then 1000 files and will delete a couple of hundred of them. What ought to be a trivial task takes nearly an hour to complete (one could do it faster manually). Can anyone suggest a more efficient algorithm? TIA.
You can save the following script as an application and then drop your source folder on it to run or you could hard code your source folder. I just tested this on a folder with 1,500 files. It deleted 800 of them in 31 seconds (PB 1.25GHz/10.3). Note that to actually delete the files, you’ll need to uncomment the “do shell script…” line. Please, please, please test on non-essential files first:
Thanks for the reply. Although this is a scheduled script and can’t be drag & drop, I think I get the idea. You are, for all intents, using Unix rather then Applescript. In otherwords you are cheating (sort of :)).
If pure Applescript is that inefficient, in this instance, that Unix is needed then I am better off writing a Unix script where it indeed is trivial.
I don’t think it’s so much that AppleScript is inefficient - in fact, in many ways it’s quite efficient), but the particulars of how the Finder deletes files is your problem in this case.
For example, the ‘delete’ command actually moves the file to the trash which forces the Finder to update that file’s location on disk, and then you later empty trash, which scans the trash folder and deletes the items within it. So essentially you’re doing twice the work. This isn’t an AppleScript limitation as much as a limitation in the Finder’s delete file implementation.
You’re also doing far more work than you need to in your script. First you get every file in the folder, then you loop through it getting “info for” each file (which forces the Finder to read all the properties of each file), then you check the date and delete the file if necessary. At the very least, you don’t need to get ‘info for’ the files since the Finder can tell you the creation date of a file without having to go through all the other ‘info for’.
A much more straighforward AppleScript implementation would be:
tell application "Finder"
set files_to_delete to every file of folder "Macintosh HD:path:to:pdf_folder:" whose creation date is less than ((current date) - 7 * days)
delete files_to_delete
empty trash
end tell
That said, removing files older than a certain date is a cinch to do in a shell script. This one-liner will do it for you:
do shell script “find /path/to/pdf_folder -mtime +7 -delete”
It also doesn’t have the inherent problem of filenames with spaces and other ‘invalid’ characters which can choke a shell script.
This was actually what I was looking for. I thought there had to be a more efficient way but I couldn’t have come up with that, from my book on Applescript, in a million years. Thanks.
‘whose’ clauses have been problematic in earlier Finder versions. The above code works on 10.3.1 (and I assume you changed the folder path to a real folder on your machine, right?)
It is not a matter of time but rather a matter of Unix. My client has an aversion to using Unix. If this is unsolvable in Applescript then I’ll just run a Unix ‘find’ command in CRONTAB.
Um, what? Is the client using OS X? If so, I’m afraid to break the news that he’s using Unix. The script above is AppleScript making some calls to Unix, just like the OS does.
Perhaps I should rephrase that. The client has a aversion to maintaining Unix scripts. They do not want to need a Unix expert to manage/maintain their systems (after I’m gone) and since OS X hides all that stuff they want to keep it that way.
I see what your script is doing but why is it faster then my original code. It appears to be doing essentially the same amout of looping except it is outside the ‘tell’ block.
Precisely because it is outside the tell block of the Finder. The Finder is painfully slow when scripting is involved (and it always has been). Also, using “list folder” and having only one move command makes it much faster as well. I’m a little confused. If someone is savvy enough to be able to maintain the pure AppleScript code, then they should be able to maintain the shell scripts embedded within it. A few simple comments would suffice. Still, 7 seconds longer for the vanilla AS version isn’t too bad.
Thanks for the explanation. I guess I am handicapped trying to learn Applescript from the books I have. No where was it clear what can be done outside the ‘tell’. It implied that all file manipulations were done by ‘Finder’. At least anything they did with files was in ‘Finder’.
Be careful with your assumptions.
Remember, the customer may not always be right but the customer is always the customer.