I have several different files in a folder (PDFs and PPTX). I need to move them to specific subfolder, depending on the first 8 characters of the filename.
File names are like this: “ANS01OTHUKE0700.pdf”. Because “UKE0700” in the end can change, the script uses a list like this:
CON00SHE
Consultants Overview
CON00PPT
Consultants Overview
COR00COV
Workbooks
COR01WKB
Workbooks
COR02WKB
Workbooks
COR03WKB
Workbooks
COR04WKB
Workbooks
COR05WKB
Workbooks
ANS01OTH
Answer Sheet
ANS02OTH
Answer Sheet
That means "if the filename starts with CON00SHE, put it in folder “Consultants Overview”. But I couldn’t make the script understand that after the first 8 chars, it should be a wildcard. So I reassembled the filename when copying.
Any suggestion?
Thank you,
Luiz
set the_list to (read ("Macintosh HD:Users:xxxxx:DestinationFoldersComplexo.txt" as alias))'s paragraphs
set {TID, text item delimiters} to {text item delimiters, tab}
set languageVersion to "UKE0700.pdf" -- this is the most possible filename end, but it can be .PPTX in some cases, what is not working
tell application "Finder"
set theFolder to (choose folder with prompt "Please choose folder to be processed")
tell application "Finder"
set newFolder to (make new folder at theFolder with properties {name:"Files to Upload to Core Units Critical Errors"})
set thefolderDest to newFolder
make new folder at newFolder with properties {name:"Additional materials"}
make new folder at newFolder with properties {name:"Consultants"}
make new folder at newFolder with properties {name:"Consultants Overview"}
make new folder at newFolder with properties {name:"Workbooks"}
make new folder at newFolder with properties {name:"Answer Sheet"}
end tell
repeat with this_para in the_list
set {source_file, new_name} to text items of this_para
set theFile to (POSIX path of ((theFolder as text) & source_file & languageVersion))
set theFileDest to (POSIX path of ((((thefolderDest) as text) & new_name & ":")) & source_file & languageVersion)
try
do shell script "cp " & quoted form of theFile & " " & quoted form of theFileDest
end try
end repeat
set AppleScript's text item delimiters to TID
end tell
set sourceFolder to alias "Macintosh HD:Users:paulskinner:Desktop:to sort:"
set sortedFiles to alias "Macintosh HD:Users:paulskinner:Desktop:sortedFiles:"
set sortTable to {{"ANS01OTH", "Answer Sheet"}, {"CON00SHE", "Consultants Overview"}, {"CON00PPT", "Consultants Overview"}, {"COR00COV", "Workbooks"}, {"COR01WKB", "Workbooks"}, {"COR02WKB", "Workbooks"}, {"COR03WKB", "Workbooks"}, {"COR04WKB", "Workbooks"}, {"COR05WKB", "Workbooks"}, {"ANS02OTH", "Answer Sheet"}}
tell application "Finder"
set fileList to (every file of sourceFolder) as alias list
repeat with thisSortEntry in sortTable
set nameRoot to item 1 of thisSortEntry
set targetFolderName to item 2 of thisSortEntry
repeat with thisFile in fileList
set thisFileName to name of thisFile
if text 1 thru 8 of thisFileName is nameRoot then
try
set thisTargetFolder to ((sortedFiles as text) & targetFolderName) as alias
on error
set thisTargetFolder to make new folder at sortedFiles with properties {name:targetFolderName}
end try
move thisFile to thisTargetFolder
end if
end repeat
end repeat
end tell
Here is the script modified to use only one repeat loop…
set sourceFolder to (path to desktop folder as text) & "to sort:"
set sortedFiles to (path to desktop folder as text) & "sortedFiles:"
try
sortedFiles as alias
on error
tell application "Finder" to make new folder at (path to desktop folder as alias) with properties {name:"sortedFiles"}
end try
set sortTable to {"Answer Sheet", "Consultants Overview", "Consultants Overview", "Workbooks", "Workbooks", "Workbooks", "Workbooks", "Workbooks", "Workbooks", "Answer Sheet"}
set rootTable to "ANS01OTH,CON00SHE,CON00PPT,COR00COV,COR01WKB,COR02WKB,COR03WKB,COR04WKB,COR05WKB,ANS02OTH"
tell application "Finder"
set fileList to (every file of folder sourceFolder) as alias list
repeat with thisFile in fileList
set thisFileName to name of thisFile
set off to offset of (text 1 thru 8 of thisFileName) in rootTable
if off > 0 then
set off to 1 + off div 9
set targetFolderName to item off of sortTable
try
set thisTargetFolder to (sortedFiles & targetFolderName) as alias
on error
set thisTargetFolder to make new folder at (sortedFiles as alias) with properties {name:targetFolderName}
end try
move thisFile to thisTargetFolder
end if
end repeat
end tell
Neater and possibly a bit more efficient with a whose clause. I did no timing tests.
set sourceFolder to (path to desktop folder as text) & "to sort:"
set sortedFolder to (path to desktop folder as text) & "sortedFiles:"
set sortTable to {{"ANS01OTH", "Answer Sheet"}, {"CON00SHE", "Consultants Overview"}, {"CON00PPT", "Consultants Overview"}, {"COR00COV", "Workbooks"}, {"COR01WKB", "Workbooks"}, {"COR02WKB", "Workbooks"}, {"COR03WKB", "Workbooks"}, {"COR04WKB", "Workbooks"}, {"COR05WKB", "Workbooks"}, {"ANS02OTH", "Answer Sheet"}}
tell application "Finder"
repeat with sortData in sortTable
set fileList to (every file of folder sourceFolder whose name begins with (item 1 of sortData)) as alias list
try
set thisTargetFolder to ((sortedFolder as text) & item 2 of sortData) as alias
on error
set thisTargetFolder to make new folder at sortedFolder with properties {name:item 2 of sortData}
end try
move fileList to thisTargetFolder
end repeat
end tell
I don’t know the full contents of the sourceFolder, but I believe that the sortTable could be reduced to three entries.
set sortTable to {{"ANS", "Answer Sheet"}, {"CON", "Consultants Overview"}, {"COR", "Workbooks"}}
Here is a solution using AppleScriptObjC.
It’s more reliable and should be faster.
If a file already exists in its destination folder, the oldest will be moved to the trash.
use framework "Foundation"
use scripting additions
set theRec to {CON00SHE:"Consultants Overview", CON00PPT:"Consultants Overview", COR00COV:"Workbooks", COR01WKB:"Workbooks", COR02WKB:"Workbooks", COR03WKB:"Workbooks", COR04WKB:"Workbooks", COR05WKB:"Workbooks", ANS01OTH:"Answer Sheet", ANS02OTH:"Answer Sheet"}
set theDict to (current application's NSArray's arrayWithObject:theRec)'s firstObject()
set theFileManager to current application's NSFileManager's |defaultManager|()
set theFolderURL to current application's NSURL's fileURLWithPath:"/Some/folder"
set theFileManager to current application's NSFileManager's defaultManager()
set theArray to theFileManager's contentsOfDirectoryAtURL:theFolderURL includingPropertiesForKeys:{} options:6 |error|:(missing value)
set theFiles to (theArray's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat:"pathExtension IN [cd] %@" argumentArray:{{"pdf", "pptx"}}))
if theFiles's |count|() = 0 then return beep
repeat with aFile in theFiles
set aParent to aFile's URLByDeletingLastPathComponent()
set aName to aFile's lastPathComponent()
set aSub to (aName's substringToIndex:8)
set aFold to (aParent's URLByAppendingPathComponent:(theDict's valueForKey:aSub))
set {theResult, theError} to (theFileManager's createDirectoryAtURL:aFold withIntermediateDirectories:true attributes:(missing value) |error|:(reference))
if not (theResult as boolean) then error (theError's localizedDescription() as string)
set aDest to (aFold's URLByAppendingPathComponent:aName)
if (aDest's checkResourceIsReachableAndReturnError:(missing value)) then (theFileManager's trashItemAtURL:aDest resultingItemURL:(reference) |error|:(missing value))
set {theResult, theError} to (theFileManager's moveItemAtURL:aFile toURL:aDest |error|:(reference))
if not (theResult as boolean) then error (theError's localizedDescription() as string)
end repeat
The OP’s script gets the file and folder data from a tab-delineated text file. FWIW, I edited Paul’s script do this.
set sourceFolder to (path to desktop as text) & "to sort:"
set sortedFolder to (path to desktop as text) & "sortedFiles:"
set dataFile to (path to desktop as text) & "Data File.txt"
try
set sortTable to getFileFolderData(dataFile)
on error
display dialog "An error occurred while reading the data file" buttons {"OK"} cancel button 1 default button 1
end try
tell application "Finder"
repeat with sortData in sortTable
set fileList to (every file of folder sourceFolder whose name begins with (item 1 of sortData)) as alias list
try
set thisTargetFolder to ((sortedFolder as text) & item 2 of sortData) as alias
on error
set thisTargetFolder to make new folder at sortedFolder with properties {name:item 2 of sortData}
end try
move fileList to thisTargetFolder
end repeat
end tell
on getFileFolderData(theFile)
set {TID, text item delimiters} to {text item delimiters, tab}
set theData to paragraphs of (read file theFile)
set theList to {}
repeat with anItem in theData
if anItem > "" then set end of theList to {text item 1 of anItem, text item 2 of anItem}
end repeat
set text item delimiters to TID
return theList
end getFileFolderData
Good point peavine. I suspect they receive a new file regularly with the data files. Here’s my take on parsing the read data.
set sourceFolder to (path to desktop as text) & "to sort:"
set sortedFolder to (path to desktop as text) & "sortedFiles:"
set sortTable to readSortData((path to desktop as text) & "Data File.txt")
tell application "Finder"
repeat with sortData in sortTable
set fileList to (every file of folder sourceFolder whose name begins with (item 1 of sortData)) as alias list
try
set thisTargetFolder to ((sortedFolder as text) & item 2 of sortData) as alias
on error
set thisTargetFolder to make new folder at sortedFolder with properties {name:item 2 of sortData}
end try
move fileList to thisTargetFolder
end repeat
end tell
on readSortData(theFile)
set theData to read ((theFile) as alias) as list using delimiter {linefeed, tab}
repeat with i from 1 to length of theData by 2
set item ((i div 2) + 1) of theData to {item i of theData, item (i + 1) of theData}
end repeat
return items 1 thru ((i div 2) + 1) of theData
end readSortData
Let’s assume for a second that you have one main folder which contains all of the files you’re talking about and within that main folder, you also have the three sub folders that you want the various files moved into (depending on the first eight characters of the file names).
This following AppleScript code allows you to choose the parent folder containing all of the files and sub folders. It will then move all of the files to the appropriate sub folders.
activate
set folderPath to quoted form of POSIX path of (choose folder)
set moveFiles to "cd " & folderPath & " sleep 1 ;mv {CON00SHE*,CON00PPT*} \"Consultants Overview/\" ;mv {ANS01OTH*,ANS02OTH*} \"Answer Sheet/\" ;mv {COR00COV*,COR01WKB*,COR02WKB*,COR03WKB*,COR04WKB*,COR05WKB*} Workbooks/"
do shell script moveFiles
If you want to trim the fat a little bit and shorten the code, this works also…
activate
set folderPath to quoted form of POSIX path of (choose folder)
do shell script "cd " & folderPath & " sleep .5 ;mv {CON00SHE*,CON00PPT*} 'Consultants Overview' ;mv ANS0*OTH* 'Answer Sheet' ;mv {COR00COV*,COR*WKB*} Workbooks"
I like to try using the least amount of code as possible. In a lot of cases I find it easier to understand exactly what’s going on. Especially if it can avoid using complex delimiters and repeat loops.