Can I automate setting pdf names to folder names

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
1 Like

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.

1 Like