I have a script that is part of a bigger code, that copies quite a few files/folders relative to certain conditions. Right now I’m accomplishing this through the Finder, but I don’t like that it creates the copying sound every time it takes action on a folder. To try and work around this, I want to convert all of this syntax into shell script, so I can do the same operations using the “do shell script” command. I’m only slightly familiar with the terminal, but not enough to fully convert the tasks I’m trying to accomplish, and when I research what I’m trying to do on forums etc, I get very confused on how to apply the answers there specifically to what I’m doing. Below is the excerpt of AppleScript that I need to convert, along with the conversion process I started, but got stuck with. Any help or suggestions would be greatly appreciated.
set floTools to (path to me as text) & "Contents:Resources:Flo Tools.kmmacros"
set views to (path to me as text) & "Contents:Resources:Flo Tools:Plug-In Views"
set source to views
set destination to (path to library folder from user domain as text) & "Application Support"
set macroSource to (path to library folder from user domain as text) & "Application Support" & ":Keyboard Maestro" & ":Keyboard Maestro Macros.plist"
set floPad to (path to me as text) & "Contents:Resources:Flo Tools:FloNumPad.app"
set appDestination to (path to applications folder as text)
set flotoolsTemplate to (path to me as text) & "Contents:Resources:Flo Tools:Flo Tools Session Template.ptxt"
set sessionTemplates to (path to home folder as text) & "Documents:Pro Tools:Session Templates"
tell application "System Events"
set checkFolder to (destination & ":Flo Tools" as text)
if not (exists folder checkFolder) then
tell application "Finder"
set folderName to "Flo Tools"
make new folder at folder destination with properties {name:folderName}
end tell
end if
end tell
tell application "Finder"
set checkBackup to (destination & ":Flo Tools" & ":Backups" as text)
if not (exists folder checkBackup) then
set folderName to "Backups"
make new folder at folder checkFolder with properties {name:folderName}
end if
end tell
tell application "System Events"
set checkViews to (destination & ":Flo Tools" & ":Plug-In Views" as text)
if not (exists folder checkViews) then
tell application "Finder"
duplicate folder views to folder checkFolder
end tell
tell me to activate
else
tell me to display alert "FloTools Plug-In Views already exist." message "FloTools has detected that you already have Plug-In Views installed. Flo Tools will now make a backup of your Plug-In Views, and store them in the Flo Tools directory of Application Support. The folder will then be merged with updated Plug-In Views from the installer. To restore user-created Plug-In Views, please copy the necessary text files from the backup." as informational buttons {"Next"} default button "Next"
tell application "Finder"
set timeStamp to do shell script "(date '+%m-%d-%Y, %I %M %S %p')"
set folderName to "Backup" & space & timeStamp
set BackupSource to (checkFolder & ":Plug-In Views" as text)
set backupFolder to make new folder at folder checkBackup with properties {name:folderName}
duplicate folder BackupSource to backupFolder
duplicate file macroSource to backupFolder
try
merge(views, checkViews)
end try
end tell
end if
if not (exists folder sessionTemplates) then
display alert "FloTools was unable to find your session templates folder. The default location for this folder is in your home directory, under Documents/Pro Tools. Please locate this folder on the next screen." buttons {"Next"} default button "Next"
tell application "Finder"
set sessionTemplatesUser to choose folder with prompt "Where is your default Pro Tools documentation and settings folder?"
set checkTemplates to (sessionTemplatesUser & ":Flo Tools" as text)
if not (exists folder checkTemplates) then
set folderName to "Flo Tools"
set tempDestination to make new folder at folder sessionTemplatesUser with properties {name:folderName}
end if
duplicate file flotoolsTemplate to tempDestination with replacing
end tell
tell me to activate
else
tell application "Finder"
set checkFloTemplates to (sessionTemplates & ":Flo Tools" as text)
if not (exists folder checkFloTemplates) then
set folderName to "Flo Tools"
set floTempDestination to make new folder at folder sessionTemplates with properties {name:folderName}
duplicate file flotoolsTemplate to floTempDestination with replacing
else
duplicate file flotoolsTemplate to (sessionTemplates & ":Flo Tools" as text) with replacing
end if
end tell
end if
end tell
set checkNumPad to (appDestination & "FloNumPad" as text)
tell application "Finder"
if not (exists file checkNumPad) then
tell me to activate
delay 2
tell me to display alert "Install FloNumPad?" message "Flo Tools comes with an additional component, called FloNumPad, which allows a standard qwerty keyboard to simulate a numpad by pressing the function key with specific letters. It is recommended that you install FloNumPad and FloTools together, but it is not required. Would you like to install FloNumPad now?" as informational buttons {"No thanks, I'll install it later.", "Yes, install now!"} default button "Yes, install now!"
set {buttonReturned} to {button returned of result}
if buttonReturned is "Yes, install now!" then
tell application "Finder"
duplicate file floPad to appDestination with replacing
end tell
end if
else
if process "FloNumPad" exists then tell application "FloNumPad" to quit
tell application "Finder"
duplicate file floPad to appDestination with replacing
end tell
delay 1
tell application "FloNumPad" to run
end if
end tell
set floTools to POSIX path of (path to me as text) & "Contents/Resources/Flo\\ Tools.kmmacros"
set views to POSIX path of (path to me as text) & "Contents/Resources/Flo\\ Tools/Plug-In\\ Views"
set source to views
set destination to POSIX path of (path to library folder from user domain as text) & "Application\\ Support"
set macroSource to POSIX path of (path to library folder from user domain as text) & "Application\\ Support" & "/Keyboard\\ Maestro" & "/Keyboard\\ Maestro\\ Macros.plist"
set floPad to POSIX path of (path to me as text) & "Contents/Resources/Flo\\ Tools/FloNumPad.app"
set appDestination to POSIX path of (path to applications folder as text)
set flotoolsTemplate to POSIX path of (path to me as text) & "Contents/Resources/Flo\\ Tools/Flo\\ Tools\\ Session\\ Template.ptxt"
set sessionTemplates to POSIX path of (path to home folder as text) & "Documents/Pro Tools/Session\\ Templates"
do shell script "mkdir -p " & destination & "/Flo\\ Tools"
do shell script "mkdir -p " & destination & "/Flo\\ Tools" & "/Backups"
Youe first problem is that you’re trying to escape spaces in POSIX paths – don’t do that. Just write a normal path, and use AppleScript’s quoted form property. For example:
set thePath to quoted form of POSIX path of (path to application support)
But if you’re not comfortable with shell scripting, an alternative is to use something like my FileManagerLib:
It has a dictionary with most of the commands you need, and you can pass files, HFS paths or POSIX paths, without having to worry about things like quoting. For example:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
use script "FileManagerLib" version "2.1"
set theFolder to create folder at somePath use name "Folder Name" -- use name is optional
My motto is always, once you’re in bash you should stay there instead creating all kind of do shell scripts, use the results for the next do shell script.
set appSupport to POSIX path of (path to application support from user domain)
do shell script "FTFolder=" & quoted form of (appSupport & "Flo Tools") & "
KBMFolder=" & quoted form of (appSupport & "Keyboard Maestro") & "
if [ -d \"$FTFolder/Plug-In Views\" ]; then
timestamp=$(date '+%m-%d-%Y, %I %M %S %p')
backupFolder=$FTFolder/Backups/Backup\\ $timestamp
mkdir -p \"$backupFolder\"
mv \"$FTFolder/Plug-In Views\" \"$backupFolder/Plug-In Views\"
#I don't have KBM installed but it should be something like this (untested):
cp \"$KBMFolder/Keyboard Maestro Macros.plist\" \"$backupFolder/Keyboard Maestro Macros.plist\"
fi
mkdir -p \"$FTFolder\"/{Backups,Plug-In\\ Views}"
This is the first part of your script including making a backup (KBM plist file untested). Since I don’t have Pro Tools installed, KBM nor FloNumPad the remainder of the script would all be a guessing game. This would get you started.
But if this script makes you too uncomfortable already, I agree with Shane. The shell is not the way to go for you.
Thank you both so much for your quick and helpful replies. This script/applet will be distributed for installation for multiple users with multiple machines, etc. which means that having them install a separate script library, or installing one for them, while super convenient for me, probably wouldn’t be the best thing. The shell script above does make me uncomfortable lol but it might force me to learn and go out of my comfort zone because it looks like that’s the only practical solution at the moment. If either of you this of something else, or if someone wants to chime in, please feel free to post back. In the meantime, I’ll mess with the code above…thanks so much
For sake of simplicity, I illuminated some parts of the script such as user dialogs, etc. when I first posted here, but as I’m trying to mess with the shell script above, I’m realizing that I need to go in and out of shell script to have applescript display dialogs, etc. unless there’s an easy way to do that while still in shell? I’ll post the entire script below for reference:
set os_version to do shell script "sw_vers -productVersion"
if os_version is less than 10.12 then
display dialog "FloTools requires Mac OS 10.12 or higher to work correctly. Please update to a compatible operating system and run the installer again." buttons {"Ok"} default button "Ok" giving up after 30
tell me to quit
end if
tell application "System Events"
if (name of processes) does not contain "VoiceOver" then
display alert "Please enable VoiceOver to continue installing FloTools." buttons {"OK"} default button "OK" giving up after 3
tell me to quit
end if
end tell
try
tell application "VoiceOver"
output ""
end tell
on error
display alert "Error!" message "This installer requires VoiceOver to be controled with AppleScript. To enable this, please go to the general tab of VoiceOver utility, and check the checkbox labeled 'Allow VoiceOver to be controld with AppleScript.' Then restart the installer." as critical buttons {"Quit", "Open VoiceOver Utility"} default button "Open VoiceOver Utility"
set {buttonReturned} to {button returned of result}
if buttonReturned is "Quit" then
tell me to quit
else if buttonReturned is "open VoiceOver Utility" then
tell application "VoiceOver Utility" to activate
tell me to quit
end if
end try
set floTools to (path to me as text) & "Contents:Resources:Flo Tools.kmmacros"
set views to (path to me as text) & "Contents:Resources:Flo Tools:Plug-In Views"
set source to views
set destination to (path to library folder from user domain as text) & "Application Support"
set macroSource to (path to library folder from user domain as text) & "Application Support" & ":Keyboard Maestro" & ":Keyboard Maestro Macros.plist"
set floPad to (path to me as text) & "Contents:Resources:Flo Tools:FloNumPad.app"
set appDestination to (path to applications folder as text)
set flotoolsTemplate to (path to me as text) & "Contents:Resources:Flo Tools:Flo Tools Session Template.ptxt"
set sessionTemplates to (path to home folder as text) & "Documents:Pro Tools:Session Templates"
try
tell application "Finder" to get application file id "com.stairways.keyboardmaestro.editor"
set doesExist to true
on error
set doesExist to false
display alert "Keyboard Maestro Not Found!" message "FloTools was unable to find the application Keyboard Maestro, which is required for FloTools to function. Please install Keyboard Maestro, and restart the FloTools Installer." as critical buttons {"OK"} default button "OK"
return
end try
if doesExist is true then
tell application "Keyboard Maestro" to set kmVersion to version
if kmVersion is less than 8.0 then
display dialog "FloTools requires Keyboard Maestro version 8.0 or higher to work correctly. Please update Keyboard Maestro to the latest version and run this installer again." buttons {"Ok"} default button "Ok"
tell me to quit
end if
end if
display dialog "To continue with the installation of FloTools, click next." buttons {"Cancel", "Next"} default button "Next" cancel button "Cancel" with title "Welcome to the FloTools Installer."
display dialog "
Flo Tools is free software. You can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your discretion) any later version.
Flo Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY, expressed or implied, of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
http://www.gnu.org/licenses/
Flo Tools collects macro usage data in order to improve the user experience. No personal information or information that could identify an individual user will be collected." buttons {"Quit", "Agree"} default button "Agree" with title "License Agreement"
set {buttonReturned} to {button returned of result}
if buttonReturned is "Quit" then
tell me to quit
end if
try
delay 1
tell application "VoiceOver" to output "Please wait while Flo Tools is being installed."
delay 1.5
end try
set progress total steps to 4
set progress completed steps to 1
set progress description to "Installing FloTools."
set progress additional description to "Please wait while Flo Tools is being installed."
delay 1
set progress completed steps to 2
set progress additional description to "Installing files."
tell application "VoiceOver" to output "Installing files."
delay 1
tell application "System Events"
set checkFolder to (destination & ":Flo Tools" as text)
if not (exists folder checkFolder) then
tell application "Finder"
set folderName to "Flo Tools"
make new folder at folder destination with properties {name:folderName}
end tell
end if
end tell
tell application "Finder"
set checkBackup to (destination & ":Flo Tools" & ":Backups" as text)
if not (exists folder checkBackup) then
set folderName to "Backups"
make new folder at folder checkFolder with properties {name:folderName}
end if
end tell
tell application "System Events"
set checkViews to (destination & ":Flo Tools" & ":Plug-In Views" as text)
if not (exists folder checkViews) then
tell application "Finder"
duplicate folder views to folder checkFolder
end tell
tell me to activate
else
tell me to display alert "FloTools Plug-In Views already exist." message "FloTools has detected that you already have Plug-In Views installed. Flo Tools will now make a backup of your Plug-In Views, and store them in the Flo Tools directory of Application Support. The folder will then be merged with updated Plug-In Views from the installer. To restore user-created Plug-In Views, please copy the necessary text files from the backup." as informational buttons {"Next"} default button "Next"
tell application "Finder"
set timeStamp to do shell script "(date '+%m-%d-%Y, %I %M %S %p')"
set folderName to "Backup" & space & timeStamp
set BackupSource to (checkFolder & ":Plug-In Views" as text)
set backupFolder to make new folder at folder checkBackup with properties {name:folderName}
duplicate folder BackupSource to backupFolder
duplicate file macroSource to backupFolder
try
merge(views, checkViews)
end try
end tell
end if
if not (exists folder sessionTemplates) then
display alert "FloTools was unable to find your session templates folder. The default location for this folder is in your home directory, under Documents/Pro Tools. Please locate this folder on the next screen." buttons {"Next"} default button "Next"
tell application "Finder"
set sessionTemplatesUser to choose folder with prompt "Where is your default Pro Tools documentation and settings folder?"
set checkTemplates to (sessionTemplatesUser & ":Flo Tools" as text)
if not (exists folder checkTemplates) then
set folderName to "Flo Tools"
set tempDestination to make new folder at folder sessionTemplatesUser with properties {name:folderName}
end if
duplicate file flotoolsTemplate to tempDestination with replacing
end tell
tell me to activate
else
tell application "Finder"
set checkFloTemplates to (sessionTemplates & ":Flo Tools" as text)
if not (exists folder checkFloTemplates) then
set folderName to "Flo Tools"
set floTempDestination to make new folder at folder sessionTemplates with properties {name:folderName}
duplicate file flotoolsTemplate to floTempDestination with replacing
else
duplicate file flotoolsTemplate to (sessionTemplates & ":Flo Tools" as text) with replacing
end if
end tell
end if
end tell
tell me to activate
delay 3
set progress additional description to "Updating macros."
set progress completed steps to 3
tell application "VoiceOver" to output "Updating macros."
if doesExist is true then
set installMacros to (path to me as text) & "Contents:Resources:Scripts:install macros.scpt"
run script file installMacros
end if
delay 1
set checkNumPad to (appDestination & "FloNumPad" as text)
tell application "Finder"
if not (exists file checkNumPad) then
tell me to activate
delay 2
tell me to display alert "Install FloNumPad?" message "Flo Tools comes with an additional component, called FloNumPad, which allows a standard qwerty keyboard to simulate a numpad by pressing the function key with specific letters. It is recommended that you install FloNumPad and FloTools together, but it is not required. Would you like to install FloNumPad now?" as informational buttons {"No thanks, I'll install it later.", "Yes, install now!"} default button "Yes, install now!"
set {buttonReturned} to {button returned of result}
if buttonReturned is "Yes, install now!" then
tell application "Finder"
duplicate file floPad to appDestination with replacing
end tell
tell me to display alert "FloNumPad has been successfully installed. However, assistive access is required for FloNumPad to function properly. Upon pressing thenext button, a system window will appear asking you to grant access to FloNumPad. Please go to System Preferences to do this, and then return to the FloTools Installer to continue." buttons {"Next"} default button "Next"
tell application "FloNumPad" to run
delay 1
tell process "universalAccessAuthWarn"
activate
set frontmost to true
end tell
tell me to display dialog "When you've successfully granted FloNumPad assistive access, click next to continue." buttons {"Next"} default button "Next" with title "Waiting for Assistive Access Permission"
delay 1
repeat until (name of processes) contains "FloNumPad"
delay 1
tell application "FloNumPad" to run
delay 1
tell application "System Events"
if (name of processes) does not contain "FloNumPad" then
tell me to display alert "Error!" message "Flo NumPad has still not been given accessibility access. Please try checking the box again in System Preferences and press next when you're ready to continue." as critical buttons {"Cancel", "Next"} default button "Next" cancel button "Cancel"
delay 1
tell process "universalAccessAuthWarn"
activate
set frontmost to true
end tell
end if
end tell
end repeat
end if
else
if process "FloNumPad" exists then tell application "FloNumPad" to quit
tell application "Finder"
duplicate file floPad to appDestination with replacing
end tell
delay 1
tell application "FloNumPad" to run
end if
end tell
set progress completed steps to 4
tell me to activate
tell application "VoiceOver" to output "Installation complete."
delay 1
display dialog "FloTools has been successfully installed." buttons {"Done"} default button "Done" with title "Installation successful."
Your code suggests it’s an applet, in which case it’s a simple matter to include the library in its bundle. Just create a folder called Script Libraries in the applet’s Resources folder, and put the library there. (You should also put it in your ~/Libraries/Script Libraries folder for development purposes.)
Wow, that’s incredible! I’m sorry…I’m like a kid in a candy store, but this makes things SO MUCH EASIER!! Thank you!!!
The only question I have is how to merge folders using the library, or another way to accomplish the same thing? Would just a simple copy object do the trick?
I’m not sure what you mean by merge. I suggest you download the library and open its dictionary – that will give you an idea of what it does and doesn’t support.
When I say merge, I’m referring to the Finder’s definition of merge; instead of replacing a folder while copying it to a location where that folder and some of it’s contents already exist, merge the 2 folders together when copying so that the destination folder has the files that were originally there and any new ones from the source. I can add the “with replacing” line to the end of the copy object statement, but if I change that to “with merging” or “merge” it doesn’t seem to do anything. I did look at the dictionary, which was extremely helpful. I’ve converted everything in the script above to syntax for the file manager library except the merging issue. Thanks so much again for all of your help; much appreciated.
I’m sorry, I’m referring to what happens when you manually copy folders through finder, and it allows you to replace or merge the folders. I believe the merge command in AppleScript allows you to do this:
set folder1 to (path to desktop) & "test1" as text
set folder2 to (path to desktop) & "test2" as text
tell application "Finder"
merge(folder1, folder2)
end tell
I did try to get objects of, and then copy object but it didn’t yield the expected result, it looked like it just copied new files, but didn’t replace files with the same name in both folders with the newer one (which was in the source folder). Here’s what I did…I’m probably missing something very simple.
use scripting additions
use theLib : script "FileManagerLib" version "2.1"
get objects of "~/Desktop/test"
copy object "~/Desktop/test" to folder "~/Desktop/test 2"
(1)As Shane already wrote, there is no merge command in Finder’s dictionary.
(2) Your copy instruction copy the folder test in the folder test 2 but if I understand well you want to copy the contents of folder test into the folder test 2.
To get what you need you must use an alternate syntax
use scripting additions
use theLib : script "FileManagerLib" version "2.1"
set orig to get objects of "~/Desktop/test"
repeat with anItem in orig
copy object anItem to folder "~/Desktop/test 2" with replacing
end repeat
Yvan KOENIG running High Sierra 10.13.4 in French (VALLAURIS, France) samedi 26 mai 2018 18:35:27
Yes, thank you. That’s much closer to what I needed, but it’s still not merging correctly, it’s just copying. I need any new files from the source copied to the destination that aren’t there, and also any files who already exist in both locations to have the newest one either copied to the destination if source is newer, or left alone if the destination is newer. Same thing that the finder does when you manually merge. Would I need to compare every file’s modification date, etc? or is there a simpler way of doing this. I can’t imagine I’m the only one who’s tried to accomplish something like this through AppleScript where someone hasn’t made a library or something similar to handle this. Thanks so much for all of your help.
Finally got a script to work Here’s my final code from a compilation of scripts:
use scripting additions
use theLib : script "FileManagerLib" version "2.1"
tell application "Finder"
tell application "System Events" to set folder1 to path of container of container of (path to me) & "Flo Tools:Plug-In Views" as alias
set folder2 to (path to library folder from user domain as text) & "Application Support" & ":Flo Tools" & ":Plug-In Views" as alias
MergeFolders({folder1, folder2}) of me
end tell
on open x
tell application "Finder"
set ErrorString to "This process needs folders to copy. At least 2 of them. Please feed folders."
if (count items in x) is less than 2 then
display dialog ErrorString buttons "OK" default button 1
return
end if
set inputFolders to {}
repeat with y in (items of x)
if last character of (y as text) is ":" then --it's a folder
set inputFolders to inputFolders & {y}
else
display dialog ErrorString buttons "OK" default button 1
return
end if
end repeat
MergeFolders(inputFolders) of me
end tell
end open
on MergeFolders(inputFolders)
tell application "Finder"
set mergeFolder to (path to library folder from user domain as text) & "Application Support" & ":Flo Tools" & ":Plug-In Views" as alias
repeat with y in (items of inputFolders)
ProcessFolder(y, mergeFolder) of me
end repeat
end tell
end MergeFolders
on ProcessFolder(inputFolder, mergeFolder)
tell application "Finder"
set inputList to list folder inputFolder
set mergeList to list folder mergeFolder
repeat with x in inputList
if x is not in mergeList then
copy object ((inputFolder as text) & x) to folder mergeFolder
else
if last character of (alias ((inputFolder as text) & x) as text) is ":" then
ProcessFolder(((inputFolder as text) & x) as alias, ((mergeFolder as text) & x) as alias) of me
else
set dateInputFile to modification date of alias ((inputFolder as text) & x)
set dateExistFile to modification date of alias ((mergeFolder as text) & x)
if dateInputFile is greater than dateExistFile then
copy object ((inputFolder as text) & x) to folder mergeFolder with replacing
end if
end if
end if
end repeat
end tell
end ProcessFolder
Don’t go wrapping everything in Finder tell blocks. The only part where deal with the Finder is the two lines where you get modification dates. Wrap them in a Finder tell block, and get rid of all other references to the Finder.
Your test for what is a folder (trailing “:”) may be problematic if you come across any packages, but that may not be an issue in your case.
So here’s a handler that should do the sort of merge you describe, using FileManager Lib:
use scripting additions
use theLib : script "FileManagerLib" version "2.1"
-- copies folder structure from source folder to destination folder, but only if there's no existing equivalent with a later modification date
-- initial values must be POSIX paths
on mergeFolders(sourceFolderPosixPath, destFolderPosixPath)
set sourceItems to objects of sourceFolderPosixPath
repeat with anItem in sourceItems
set theName to full_name of (parse object anItem)
set destPath to destFolderPosixPath & "/" & theName
if (object is folder anItem) then
if exists object destPath then -- we assume it too is a folder
my mergeFolders(anItem, destPath)
else
copy object anItem to folder destFolderPosixPath
end if
else
if exists object destPath then
set sortedList to sort objects {anItem, destPath} sorted property modification property
if item 1 of sortedList is not equal to contents of anItem then
copy object anItem to folder destFolderPosixPath with replacing
end if
else
copy object anItem to folder destFolderPosixPath
end if
end if
end repeat
end mergeFolders