Listing the names of folders that have folders in a specific subfolder

Hello folks!

I’m working on a script to display all clients in a list (from directory with PDF previews) that have jobs located in a folder called žfinished" (so I know what to put into the archive) and then use that list to open folders from the main directory.

That’s the folder structure:

PDFdirectory
”- client1
”-”- finished
”-”-”- finishedjob1
”-”-”- finishedjob2
”-”- activejob1
”-”- activejob2
”-”- activejob3
”- client2
”-”- finished
”-”- activejob1
”-”- activejob2
”- client3
”-”- finished
”-”-”- finishedjob1

(Maindirectory
”- client1
”- client2
”- client3
”- client4)

The result of running the script over these folders would be this list:

client1
client3

That’s what I wrote so far:

set the finished_jobs to ""

on open (theList)
	repeat with theFolder in theList
		set theFolder to theFolder as string
		if (theFolder ends with ":") then
			doCheck(theFolder)
		end if
	end repeat
	display dialog finished_jobs with title "Report" with icon 1 buttons {"OK"} default button 1
end open

on doCheck(theFolder)
	try
		tell application "Finder"
			set theList to the name of every folder in the folder theFolder whose name is "finished"
			repeat with f in theList
				my doCheck(theFolder & f & ":")
			end repeat
			
			set n to number of folders in folder theFolder
			if (n > 0) then
				set the finished_jobs to the finished_jobs & ¬
					"" & return
			end if
		end tell
	end try
end doCheck

But somehow I need to check the second hierarchy separately so I could return the client names as a result .
Any help is much appreciated!

Best regards,
hof

Model: Mac Pro
AppleScript: 2.7 (176)
Browser: Safari 537.36
Operating System: Mac OS X (10.10)

Here’s an alternative using AppleScriptObjC.

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

on searchDirectory:posixPath
	-- make mutable array to hold list of clients
	set theClients to current application's NSMutableArray's array()
	-- get file manager
	set fileManager to current application's NSFileManager's defaultManager()
	-- make URL of folder to search
	set theURL to current application's class "NSURL"'s fileURLWithPath:posixPath
	-- get enumerator, skipping packages and invisibles
	set theEnumerator to fileManager's enumeratorAtURL:theURL includingPropertiesForKeys:(missing value) options:((current application's NSDirectoryEnumerationSkipsPackageDescendants) + (current application's NSDirectoryEnumerationSkipsHiddenFiles as integer)) errorHandler:(missing value)
	repeat -- loop through URLs
		-- if 2 levels deep, go no further
		if theEnumerator's level() as integer > 1 then theEnumerator's skipDescendents()
		-- get next URL
		set thisURL to theEnumerator's nextObject()
		-- if missing value, there are no more
		if thisURL is missing value then exit repeat
		-- if name is "finished" get the component before the name
		if (thisURL's lastPathComponent() as text is "finished") then
			set folderItems to fileManager's contentsOfDirectoryAtURL:thisURL includingPropertiesForKeys:(missing value) options:(current application's NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
			if folderItems's |count|() > 0 then
				theClients's addObject:(thisURL's URLByDeletingLastPathComponent()'s lastPathComponent())
			end if
		end if
	end repeat
	return (theClients's componentsJoinedByString:", ") as text
end searchDirectory:

set theClients to its searchDirectory:"/Users/shane/Desktop/PDF directory"
-->	"client1, client2, client3"

Edited to check folder is not empty

Hi hof. Welcome to MacScripter.

Here’s a another approach using a shell script. It relies on the fact that when ‘posix path of’ is applied to a folder alias, the resulting path ends with a slash. When such a path is fed to ‘find’, the paths returned have two slashes at this point. ‘find’ can also be set to return only paths in which “/finished” is followed by a slash and other characters, meaning the relevant “finished” folder has something in it. The ‘sed’ code parses out the client names and ensures there’s only a single instance of each.

set pdfFolder to (choose folder)

set shellScript to "# Get every path in the hierarchy containing '/finished/' (2 slashes) and where the name does not begin with a dot.
find " & quoted form of POSIX path of pdfFolder & " \\( -path '*/finished/*' -or -path '*/Finished/*' \\) -and -not -name '.*' |
sed -n '
# Extract the client name from each path (between the double slash and the next single one).
s|.*//\\([^/]*\\)/.*|\\1|
# Append a linefeed and it to the hold space. (The linefeed simplifies the identification of duplicates below.)
H
# If it's the same as the previous name, drop it.
2,$ {
	g
	s|\\(.*\\(\\n.*\\)\\)\\2$|\\1|
	$ !h
}
# After processing the last name, return the completed list without the initial linefeed.
$ s|^\\n||p'"

do shell script shellScript

Nigel,

As posted, it already ignores empty finished folders here.

Anyway, here’s a third version, using the Finder:

set pdfFolder to alias "Macintosh HD:Users:shane:Desktop:PDF directory:"

tell application "Finder"
	set theFolders to folders of folders of pdfFolder as alias list
end tell
set theClients to {}
set saveTID to AppleScript's text item delimiters
set AppleScript's text item delimiters to {":"}
repeat with aFolder in theFolders
	tell application "Finder"
		if (aFolder as text) ends with ":finished:" and (count of items of aFolder) > 0 then
			set end of theClients to text item -3 of (aFolder as text)
		end if
	end tell
end repeat
set AppleScript's text item delimiters to saveTID
return theClients

Interestingly, the Finder version is not too shabby performance-wise. It’s about half the speed of the shell version in my small test here – if the finished folders are (near) empty. But as I add a few items to the finished folders, it soon becomes faster than the shell version – presumably because, like the ASObjC method, it doesn’t traverse the full hierarchy.

Edited to check folder is not empty

Hi Shane.

Both your scripts return the names of all the client folders containing “finished” folders. Mine returns only the names of client folders whose “finished” folders aren’t empty, which is the nearest I can currently get to my understanding of hof’s requirements. If the “finished job” names could be relied upon uniquely to contain some sequence such as “finishedjob”, it would be possible to tighten up the code to return only client names where the “finished” folders specifically contained finished jobs.

Quite right – I misread the requirements. I’ve since adjusted the scripts to suit.

Nigel,

I’m possibly doing something wrong, but your script seems to be returning a doubled-up name in some circumstances. It looks like it happens if the first non-empty folder it comes across has more than one item.

Thanks, Shane. It appears to have been due to a last-minute adjustment I made while posting! Reverting to the original seems to have fixed it, but I’ll have to look at it more closely to understand why.

Been there, done that :slight_smile:

I must try to learn the lesson… :rolleyes:

My original sed code removed any text sequence which duplicated an immediately preceding sequence. My bad adjustment was an attempt to make sure this could only happen right at the end of what had been gathered so far. I’ve now adjusted it again so that the whole of the last line has to be the same as the whole of the preceding line to be considered a duplicate. (In fact, I think it would also consider the last two or more lines to be a duplicate if they were the same as the two or more before, but that won’t happen here.)