I have a bunch of subfolders in 1 folder, and in those subfolders I have pdf’s. I want to make a script that would automatically set each pdf to the subfolders name
What if there are multiple pdfs in a subfolder?
Ok i should probably clarify, i want the subfolders name added infront of pdf’s name.
example
001.pdf - - → {subfolder} 001.pdf
Just for practice, I wrote a shortcut that does what the OP wants. The shortcut skips files that had previously been renamed to begin with the file’s parent folder.
The target folder has to be set in the File action immediately below the Comment action. This shortcut should be tested on backup copies of files only, and it’s important to note that this shortcut works recursively.
Rename PDFs.shortcut (23.0 KB)
This following AppleScript code assumes you have one main folder with no .pdf files in that folder. However, that main folder does have sub folders and each one of those sub folders has .pdf files you want to rename. Running this code will ask you to choose that main folder, containing the sub folders.
activate
set posixFolderPath to quoted form of POSIX path of (choose folder)
set subFolders to paragraphs of (do shell script "cd " & posixFolderPath & ¬
" ;find \"$PWD\" " & posixFolderPath & ¬
" -type d -mindepth 1 |tr -s '//' |sort -f |uniq")
repeat with i in subFolders
set bName to quoted form of (do shell script "basename " & quoted form of i)
do shell script "cd " & quoted form of i & " ;for f in *.pdf ;do mv \"$f\" " & ¬
bName & "_" & "\"$f\" ;done"
end repeat
Your files will be renamed from ex: 001.pdf to subfolder_001.pdf
@Spaghetint I saw your deleted post and I found the problem and updated my code. I originally did not take into consideration that your main folder may have spaces in the name. Just do me a favor and test my code again please and see if you have any more problems
The following is a simple AppleScript solution. It works as expected but will be slow (and may fail) if the number of PDF files is large.
set theFolder to (choose folder)
tell application "Finder"
set theFiles to every file in the entire contents of theFolder whose name extension is "pdf"
display dialog "The selected folder contains " & (count theFiles) & " PDF files?" --disable if desired
repeat with aFile in theFiles
set aFileName to name of aFile
set aParentFolder to name of parent of aFile
if aFileName does not start with aParentFolder then set name of aFile to (aParentFolder & " - " & aFileName)
end repeat
end tell
Thanks for updating you code, Ill try it again in a bit and tell you if there are an problems
wch1zpink. I tested your script and got the following error message:
mv: Folder_Repeat Loops.pdf is not a directory
mv: Folder_User Defaults.pdf is not a directory
The folder that contained the test files was:
/Volumes/Store/Save/Test Folder/
The above folder contained the following files:
/Volumes/Store/Save/Test Folder/Repeat Loops.pdf
/Volumes/Store/Save/Test Folder/User Defaults.pdf
When running the script I selected the following folder in the choose folder
dialog:
/Volumes/Store/Save/
@peavine Nothing that just simply changing set bName to
to… set bName to quoted form of
couldn’t fix. LOL
activate
set posixFolderPath to quoted form of POSIX path of (choose folder)
set subFolders to paragraphs of (do shell script "cd " & posixFolderPath & ¬
" ;find \"$PWD\" " & posixFolderPath & ¬
" -type d -mindepth 1 |tr -s '//' |sort -f |uniq")
repeat with i in subFolders
set bName to quoted form of (do shell script "basename " & quoted form of i)
do shell script "cd " & quoted form of i & " ;for f in *.pdf ;do mv \"$f\" " & ¬
bName & "_" & "\"$f\" ;done"
end repeat
I retested and it works great.
I took the liberty to test the timing of several different variations of your code. The selected folder contains five sub folders… Each of which contains 100 PDF files (500 PDFs will be renamed).
I find the results quite interesting.
Version 1 - Script Timer: 55.01s
set theFolder to (choose folder)
tell application "Finder"
with timeout of 700 seconds
set theFiles to (every file in the entire contents of theFolder whose name extension is "pdf")
end timeout
repeat with aFile in theFiles
set aFileName to name of aFile
set aParentFolder to name of parent of aFile
if aFileName does not start with aParentFolder then set name of aFile to (aParentFolder & " - " & aFileName)
end repeat
end tell
Version 2 - Script Timer: 45.00s
set theFolder to (choose folder)
tell application "Finder"
with timeout of 400 seconds
set theFiles to (every file in the entire contents of theFolder whose name extension is "pdf") as alias list
end timeout
repeat with aFile in theFiles
set aFileName to name of aFile
set aParentFolder to name of parent of aFile
if aFileName does not start with aParentFolder then set name of aFile to (aParentFolder & " - " & aFileName)
end repeat
end tell
Version 3 - Script Timer: 37.97s
set theFolder to (choose folder)
tell application "Finder"
with timeout of 400 seconds
set theFiles to (every file in the entire contents of theFolder)
end timeout
repeat with aFile in theFiles
if name extension of aFile = "pdf" then
set aFileName to name of aFile
set aParentFolder to name of parent of aFile
if aFileName does not start with aParentFolder then set name of aFile to (aParentFolder & " - " & aFileName)
end if
end repeat
end tell
Version 4 - Script Timer: 11.54s
set theFolder to (choose folder)
tell application "Finder"
with timeout of 400 seconds
set theFiles to (every file in the entire contents of theFolder) as alias list
end timeout
repeat with aFile in theFiles
if name extension of aFile = "pdf" then
set aFileName to name of aFile
set aParentFolder to name of parent of aFile
if aFileName does not start with aParentFolder then set name of aFile to (aParentFolder & " - " & aFileName)
end if
end repeat
end tell
Version 5 - Script Timer: 7.72s
activate
set posixFolderPath to quoted form of POSIX path of (choose folder)
set subFolders to paragraphs of (do shell script "cd " & posixFolderPath & ¬
" ;find \"$PWD\" " & posixFolderPath & ¬
" -type d -mindepth 1 |tr -s '//' |sort -f |uniq")
repeat with i in subFolders
set bName to quoted form of (do shell script "basename " & quoted form of i)
do shell script "cd " & quoted form of i & " ;for f in *.pdf ;do mv \"$f\" " & ¬
bName & "_" & "\"$f\" ;done"
end repeat
So when i test out version 5 of the code i get this error message
error “mv: rename [file names] File name too long” number 1
[file names] is not part of the actual error, i just had to ommit the names due to privacy
@Spaghetint Make sure you only select the folder which contains the sub folders which contain the PDF files
If the number of PDF files being processed is large, an ASObjC script might be considered. The following script took 99 milliseconds to rename 548 PDF files in a target folder that contained 565 total files in 135 folders. As noted before, please test this script with backup file copies.
use framework "Foundation"
use scripting additions
on main()
set theFolder to "/Volumes/Store/Save/" --set to target folder
set theFiles to getFiles(theFolder, {"pdf"})
display dialog ((theFiles's |count|()) as text) & " PDF files were found in the selected folder" buttons {"Cancel", "Rename"} cancel button 1 default button 1 --disable if desired
repeat with aFile in theFiles
set aFolder to aFile's URLByDeletingLastPathComponent()
set parentFolderName to aFolder's lastPathComponent()
set fileName to aFile's lastPathComponent()
if (fileName's hasPrefix:parentFolderName) is false then
set newFileName to current application's NSString's stringWithFormat_("%@ - %@", parentFolderName, fileName)
set newFile to (aFolder's URLByAppendingPathComponent:newFileName isDirectory:false)
try
renameFile(aFile, newFile)
on error theError
display alert quote & fileName & quote & " could not be renamed and will be skipped" message theError
end try
end if
end repeat
end main
on getFiles(theFolder, fileExtensions)
set theFolder to current application's |NSURL|'s fileURLWithPath:theFolder
set fileManager to current application's NSFileManager's defaultManager()
set folderContents to (fileManager's enumeratorAtURL:theFolder includingPropertiesForKeys:{} options:6 errorHandler:(missing value))'s allObjects() --options 6 skips hidden files and package contents
set thePredicate to current application's NSPredicate's predicateWithFormat_("pathExtension.lowercaseString IN %@", fileExtensions)
return folderContents's filteredArrayUsingPredicate:thePredicate
end getFiles
on renameFile(theFile, renamedFile)
set fileManager to current application's NSFileManager's defaultManager()
set {theResult, theError} to fileManager's moveItemAtURL:theFile toURL:renamedFile |error|:(reference)
if (theResult as boolean) is false then error (theError's localizedDescription() as text)
end renameFile
main()
wch1zpink. My apologies for not carefully reading your post, which makes two important points about working with Finder:
-
the use of whose clauses to filter files can significantly slow a script; and
-
setting files to an alias list can make a script faster.
People occasionally complain when I use Finder to perform some task, and I thought that was the purpose of your post, which clearly it wasn’t. Sorry about that!
There are several reasons people complain about using Finder to perform some tasks with AppleScript. The main reason I believe is because System Events has a lot of commands which do the same function and are considerably faster than the Finder commands. (especially when it comes to iterating through a list for copying, duplicating, moving, renaming files etc.)
So the unwritten and unspoken rule of thumb is basically, only use Finder AppleScript commands to do what System Events commands cannot accomplish, then switch over to System Events commands to handle all of the “heavy lifting”. It’s much much quicker that way. For example, from the AppleScript code in your earlier post, my approach would have been using Finder AppleScript commands to create the alias list of files (because System Events can’t create the alias list of files), then System Events commands to loop through that list of files to rename them.
Sometimes it’s not that big of a deal to just use Finder commands to accomplish everything if you’re only dealing with a small number of items to process.
I just thought you may find it interesting how just a few subtle variations of your AppleScript code could make a major difference with performance. I wasn’t critiquing… I just thought you may find it useful.