I'm looking for a neat solution to the following workflow, I think it's going to have to be scripted and unfortunately that surpasses my knowledge so I was hoping for some advice
I'm currently running a large macros, but it's clunky and relies a lot on the UI. Part of it involves moving 24 files (file names are integers, it's always the first 24 from the folder that are moved) from one folder (fixed, on an external drive) to a folder that has been created (the path is always the same, but the folder name is set to a variable earlier in the process). Due to automating the opening of the finder window, selecting the first 24 files in the folder, opening up the new folder and moving the files that way, it's quite time consuming and doesn't allow the rest of the process until it's completed. As the macros is looped sometimes 12 times and the files are quite large, hanging on until the progress window has disappeared can add 10 mins plus to the whole process.
Now without the lengthy explanation -
Need to move files 1-24 from fixed folder a, to variable folder b. Files have a different name each time.
In addition to @ccstone's questions: Can you post some example file names? Are they eg "1-Myfile".."24_Myfile" or "01_Myfile".."24_Myfile"? Coz the second makes life a lot easier (ASCII sort, FTW!).
Does the macro need to process the files after they've been moved, or does it go on to other things not involving those files? Is it actually a "move" (ie within the same volume), a copy (ie from one volume to another, keeping the original), or a "copy-then-delete-original"? (It sounds like it's either the second or third, as a single volume "move" should be very quick.)
This is the set path for the folder that the files are in -
/Volumes/DRIVE 256/RNR/Master
The new folder is here -
/Users/adam/Final/variablefolder
The number of files in the fixed folder changes. It get loaded up with files which get processed each time, so could be in the 10s, or occasionally the 1000s.
The files themselves are usually around 30MB, and the name is always an integer, for example the first few in there at the moment are -
0048645
0048690
0048736
0048784
0048853
It is essentially a copy and delete task, you are correct.
Assuming that the files are as per your example and "the first 24" is "the first 24, by name, using ASCII sort order" here's something you could try. It is destructive since it includes the delete step, so work on copies of your files!
Make a new folder on the "DRIVE 256" volume and duplicate 30-40 sample files from your "Master" folder into it. Make a test destination folder in /Users/adam/Final/
Copy the following into a new document in the Script Editor application:
tell application "Finder"
set sourceFolder to (choose folder with prompt "Pick a source folder:")
set destinationFolder to (choose folder with prompt "Pick a destination:")
set sourceFiles to (items 1 thru 24 of (every item of sourceFolder sort by name)) as alias list
repeat with eachItem in sourceFiles
try
duplicate eachItem to destinationFolder
on error
-- log an error here
exit repeat
end try
delete eachItem
end repeat
end tell
...and run it, choosing your test folder with the duplicate files in the first dialog and your test destination in the second. You'll get a Finder "bong" after every file is copied, just to let you know things are happening -- you may want to turn your volume down a touch while testing
I've done this one file at a time so you can handle an error on any file copy -- as written it will only delete a file after a successful copy and will exit the loop on an error, leaving you with some files copied (and deleted) and the rest not. Have a think about how you want to handle errors, whether you'd like successful copying to be logged to a file, etc.
If the script does what you want it's easy to include it as a KM action, feeding in the destination folder (and even the source, for portability) as a KM variable calculated earlier in the macro, and add improvements (like muting your sound for the duration!).
Incredible, thank you Nige! Worked exactly as it should, particularly enjoying the bongs
The next step for me is fixing the sourceFolder location (done in the script?) and somehow using the folderName var from KM to automate destinationFolder, which I feel maybe more complicated. I'm thinking for destinationFolder a text input popup that can be filled from KM, is that possible? Or is there an easier way?
I did try setting the sourceFolder location, however 8 days into learning swift and no knowledge of any other language, I wasn't even able to do that! Sorry for there being this barrier, I was really hoping I could take what you've given me already and run with it!
If the source folder never changes, you should be able to set it this way:
set sourceFolder to POSIX file "/Volumes/DRIVE 256/RNR/Master"
In the spirit of @Nige-S's script, you can make this slight tweak to the code that handles the destination folder:
set destinationParent to POSIX file "/Users/adam/Final"
set destinationFolder to choose folder with prompt "Select or create a destination folder" default location destinationParent
This will bring up the folder picker dialog already in /Users/adam/Final and you'll be able to either select an existing folder or use the New Folder button to make and name a new one on the fly. This is, I think, more Mac-like (and more flexible) than using a Keyboard Maestro dialog to get the name of the new folder.
Building on this -- If you are anything like me, you'll frequently forget to turn on/plug in the external drive
set sourceFolder to POSIX file "/Volumes/DRIVE 256/RNR/Master"
set driveAvailable to ""
repeat while driveAvailable = ""
try
set driveAvailable to sourceFolder as alias
on error
display alert "Please plug in the external drive!" as critical giving up after 10
delay 20
end try
end repeat
...which flashes an alert if the volume isn't mounted, waits 20-30 seconds (depending on whether you manually dismiss the dialog), and tries again. If you're running this script unattended you might prefer to do something different if the volume isn't mounted, eg send an email to the "admin" and abort the macro.
I haven't got as far as dialogs in the KM manual yet, but would agree with the good Doctor -- for a standard Mac activity like choosing a file it makes more sense (and will be easier for you or another user) to use a standard Mac dialog.
But seeing @drdrang's name here reminds me of a point he often makes in his excellent blog[1] -- scripting isn't just about removing the tedium of doing something repeatedly by hand. It's also -- and perhaps more importantly -- about removing opportunity for user error. I would assume you've some logic to your destination folders' structure -- can you leverage that and calculate the destination within the script (or earlier in the KM macro), no user interaction required? Start by thinking about (or posting!) how the user currently chooses/creates the correct destination folder, and how you could use the data available to KM/AppleScript (eg current date and time) to replicate that -- or even improve on it!
[1] Being a newbie here, I'm unsure about the correctness of recommending another member's blog. Mods, feel free to edit/delete and chastise me. @drdrang -- if my fawning embarrasses you do let me know, but it really is an excellent blog...
Thanks again for all this help - I'm learning too which is great! The POSIX fix for sourceFolder is throwing up an error however, after selecting destinationFolder and trying to do the move...
error "Finder got an error: Can’t get every item of file "DRIVE 256:RNR:Master Test:"." number -1728 from everyitemoffile "DRIVE 256:RNR:Master Test:"
Any ideas?
edit: I should add there are enough files in the folder
The KM macro is meant to be run without any user input - the folder is generated earlier in the process in which the name is input from a variable, taken from a spreadsheet. There is no logic unfortunately, and as the folder is already created and new spreadsheets saved in it, we can't generate it at this point.
I'm not concerned about the ext drive not being connected as it's used for other purposes in the process so it'll have to be connected for the macro to run anyway, but that's a very good shout and I appreciate how you think of the little things like that!
As a possibility, I think a crude workaround to automating the destinationFolder selection could be when the destinationFolder dialog pops, KM typing the variable out which should select the correct folder.
Try coercing sourceFolder to an alias (which I forgot to do in my loop demo ), eg:
set sourceFolder to POSIX file "/Volumes/DRIVE 256/RNR/Master Test/"
set sourceFolder to sourceFolder as alias
Then, since the information is already known, it's easy to add it in to the script logic. Assuming the saved destination folder name (just the name, not the path!) is in the KM variable "Folder Name" then add this at the start of the AppleScript we've been developing. Writing it out long-hand, so you can see each step:
tell application "Keyboard Maestro Engine"
set destFolderName to getvariable "Folder Name"
end tell
tell application "Finder"
set destinationParent to "/Users/adam/Final/"
-- combine the two strings, coerce to a POSIX path, and coerce that to a Finder alias
set destinationFolder to (destinationParent & destFolderName) as POSIX file
set destinationFolder to destinationFolder as alias
set sourceFolder to POSIX file "/Volumes/DRIVE 256/RNR/Master Test"
set driveAvailable to "No"
repeat while driveAvailable = "No"
try
set sourceFolder to sourceFolder as alias
set driveAvailable to "Yes"
on error
display alert "Please plug in the external drive!" as critical giving up after 10
delay 20
end try
end repeat
-- after all that, we get to do the copying!
set sourceFiles to (items 1 thru 24 of (every item of sourceFolder sort by name)) as alias list
repeat with eachItem in sourceFiles
try
duplicate eachItem to destinationFolder
on error
-- log an error here
exit repeat
end try
delete eachItem
end repeat
end tell
As always -- test with "disposable" files first, troubleshoot and tweak, and be certain you're happy before going into "production"! If you're having problems, post your macro.
Thanks a lot, I really do appreciate all the help you've given me! I'll add it into the macro and run the whole thing to see how it does. No worries RE as alias, I didn't even know it was a thing until today
Sorry for the delay on getting back - tested it in the macro last night and it threw up an error, unfortunately working on other things today so was delayed on the reply.
Luckily that delay helped me see clearly. The error was -
text-script :992:992: script error:
Expected “given”, “with”, “without”, other parameter name, etc. but found end of script.
And the issue was.... human! I didn't select all on the script, so copied without the last few lines So in fact it works perfectly and is fully integrated now. Thanks so much for all your help, it really is much appreciated.
Now time to get my head into VBA for Excel to get rid of the endless keystroke actions.. Anyone know the directions to that forum?