Return a list of Folders and Subfolders

Hi

This may have been answered but I have not so far been able to find it. I need a script that first creates a list of all the folders in say My documents, check names against a subject name to see if there is on the same or close and then returns the path of that folder. I have not got far even this script does not work it gets all the names . But I cannot even list them so don’t know how I can check them .

set theFolder to choose folder
tell application "Finder"
	set thefolders to every folder of entire contents of theFolder
	
	repeat with i from 1 to count of thefolders
		--this fails basis intotype text or string
		
		--display dialog i of thefolders as text
		
		
		display dialog path of i of the folders as text
	end repeat
end tell

My objective is to check subject of incoming emails if similar to an existing folder want to place a copy in that folder then flag the email.

thanks

Peter

Hi, Peter. Your choice of variable, i, isn’t very descriptive, so you might not readily see it as being a number. You’re asking for the path of an integer of the folders, which isn’t an object. Your loop would’ve worked like this:

repeat with i from 1 to count thefolders
		display dialog thefolders's item i as string
	end repeat

I think this is basically what you’re trying to do:

tell application "Finder" to ((path to documents folder)'s entire contents's folders whose name is in my getList())


on getList()
	tell application "Mail" to inbox's message's subject
end getList

–edited for typo

Hi Marc

Thanks for the quick reply. I have tried your first change to get the script working and I am still missing something. the Test folder I use has 2 subfolders. It displays the full path for each of the subfolders and then fails on item 3 “cannot make it into type string”. Interestingly when I count the folders in “the folders” it returns 4 and there are only 3 any ideas.

set theFolder to choose folder
tell application "Finder"
	set thefolders to every folder of entire contents of theFolder
	display dialog (count of thefolders)
	repeat with i from 1 to count of thefolders
		
		display dialog theFolder's item i as string
		
		
	end repeat
end tell

thanks again

peter

You probably mean:

       display dialog item i of thefolders as string

But before you go much further you should know that the Finder’s entire contents is notoriously unreliable (and slow) with folder containing a lot of items and subitems.

Hello!

Here is a handler that will return the posix path of a folder containing your subject. You should feed it the posix path of the root folder of your subject folder.

If you use the handler from within a mail tell block, then prepend it with the keyword my. It is generally easier to use System Events for file operations, as long as you don’t need user interaction with the Finder.


set thefolders to my findFolderOnly(searchterm, directoryToSearchIn)

on findFolderOnly(searchterm, directoryToSearchIn)
	set searchterm to "\"*" & searchterm & "*\""
	try
		return first paragraph of (do shell script "mdfind -onlyin " & directoryToSearchIn & " 'kMDItemFSName  == " & searchterm & " && ( kMDItemContentType == \"public.folder\" || kMDItemFSSize == 0 )' ")
	on error
		return {}
	end try
end findFolderOnly

Hi Shane & McUsr

thank you both for your replies. Shane you were correct the moment I saw your post I realised the mistake I had made. I have not worked with finder like this before so I will heed your advice. As what I am looking for is a search list that I can compare an email subject with and that I do not change my folder construction that often. I am going to work on creating a index/list of all my folders which I can update as required. That will avoid having to use finder on each occasion do you think that makes sense?

McUsr, assuming creating a list of all existing folders in a separate operation works then am I correct in thinking that in your script the “searchterm” would be the subject from the email and “directortytosearchin” becomes the list?

thanks again your help is very much appreciated.

Peter

Possibly. See how long something like mdfind takes, or you can even use my ASObjC Runner and its enumerate folder command. They might be fast enough to avoid having to think about whether your index is up-to-date.

Yes. “directortytosearchin” would be the folder enclosing all of the others, the “root-folder for the subtree”.

Hi Shane and McUsr

Once again my thanks I have progressed a little, and if you have time I still need some advice.

Shane I have not used mdfind and my research did not help much so I have gone back to trying to create a list. Have managed to copy it to the clip board but so far have not been able to create a document I could open and check against . Time may get me there my real request is that while I have now managed a list which will have all the folder names as I am only going to compare (subject maybe sender) with the folder name I need an index so that I will then put the mail in the correct folder. Any suggestions please.

This by the way is the scrip that I use to create list.

tell application "Finder"
	
	set folderpath to (choose folder) -- sets file path to folders selected
	set thefolders to every folder of entire contents of folderpath
	repeat with objItem in thefolders
		set ParentFolder to container of objItem -- sets the parent folder
		set Foldername to name of objItem as text -- sets the folder name as text
		--The dialog box shows, Path to Folder, Parent Folder and Folder name
		
		display dialog "Path to Folder " & objItem & return & "Parent Folder of Folder " & ParentFolder & return & "Name of Folder " & Foldername
	end repeat
	
	
end tell

Peter

You’re going to need to save the data in a file, and there are lots of ways. Probably the simplest would be to get just the full paths to the folders, and save them as a text file, one per paragraph. Then you can read in the paragraphs of the file, and loop through looking for an entry that ends with the required name.

But depending on the number of folders involved, this may end up slower than mdfind or enumerate folder – AppleScript can get slow with very long lists.

Hello!

Mdfind searches the disk as fast as Spotlight does. This alleviates the need for creating a list, that may quickly come out of sync anyway. I have adopted the handler to your script, please try this. :slight_smile:

Try it with a subject you have, and one you don’t have. If it takes more than a whisker when using a subject you have for sure, try to search for that term with spotlight: ( kind:folder your_subject), if spotlight doesn’t give you the answer right away (possibly among many others), then something may be corrupted with spotlight.

Then you should empty hardware caches and restart your computer, before rebuilding the spotlight index. Onyx is great for emptying caches. The rest you will find by google.


set folderpath to quoted form of (POSIX path of (choose folder)) -- sets file path to folders selected

set subject to "Multimedia"

set objItem to my findFolderOnly(subject, folderpath)
if objItem is not {} then
	
	tell application "System Events" to tell disk item objItem to set {ParentFolder, Foldername} to {POSIX path of container of it, name of it}
	
	display dialog "Path to Folder:" & objItem & return & "Parent Folder of Folder " & ParentFolder & return & "Name of Folder: " & Foldername
else
	display dialog "Not found"
end if


on findFolderOnly(searchterm, directoryToSearchIn)
	set searchterm to "\"*" & searchterm & "*\""
	try
		return first paragraph of (do shell script "mdfind -onlyin " & directoryToSearchIn & " 'kMDItemFSName == " & searchterm & " && ( kMDItemContentType == \"public.folder\" || kMDItemFSSize == 0 )' ")
	on error
		return {}
	end try
end findFolderOnly

Hi McUsr

Cannot thank you guys enough for all your help but I cannot get it to work correctly. I think it has something to do with spaces in the starting folder name. At Desktop I have the following folders

A New Test Folder
ApplescriptTest.
Test 2
sub2
Sub1
Test1
When I set the subject to “sub2” I get not found and this is what I get
tell application “AppleScript Editor”
choose folder
end tell
tell application “AppleScript Editor”
choose folder
→ alias “Macintosh HD:Users:mitch:Desktop:A New Test Folder:”
end tell
tell current application
do shell script "mdfind -onlyin /Users/mitch/Desktop/A New Test Folder/ ‘kMDItemFSName == "sub2" && ( kMDItemContentType == "public.folder" || kMDItemFSSize == 0 )’ "
→ error “Failed to create query for ‘New Test Folder/ kMDItemFSName == "sub2" && ( kMDItemContentType == "public.folder" || kMDItemFSSize == 0 )’.” number 1
end tell
tell application “AppleScript Editor”
display dialog “Not found”
→ {button returned:“OK”}
end tell
Result:
{button returned:“OK”}

I set up the folders from Applesxript Test in Desktop

ApplescriptTest.
Test 2
sub2
Sub1
Test1

and it works this is the result.
tell application “AppleScript Editor”
choose folder
end tell
tell current application
do shell script "mdfind -onlyin /Users/mitch/Desktop/ApplescriptTest/ ‘kMDItemFSName == "sub2" && ( kMDItemContentType == "public.folder" || kMDItemFSSize == 0 )’ "
end tell
tell application “System Events”
get POSIX path of container of disk item “/Users/mitch/Desktop/ApplescriptTest/Test 2/sub2”
get name of disk item “/Users/mitch/Desktop/ApplescriptTest/Test 2/sub2”
end tell
tell application “AppleScript Editor”
display dialog “Path to Folder:/Users/mitch/Desktop/ApplescriptTest/Test 2/sub2
Parent Folder of Folder /Users/mitch/Desktop/ApplescriptTest/Test 2
Name of Folder: sub2”
end tell
Result:
{button returned:“OK”}

I thought it may have been the number of levels “sub2” is 4 down from desktop in the failed example and only 3 down in the one that worked.
I then removed the spaces in the folder I started with and it works. It does not seem to matter if the subject has spaces just the starting point.

Having said that I tried looking for a file under “Documents” (no spaces) on my hard drive that did not work.

Sorry to ask again but can you help I guess I have to pad the name of the starting folder somehow.

thanks

Peter

Does not seem to like external drives either. I copied the exact file structure from Desktop to an external drive Same error.

tell current application
do shell script "mdfind -onlyin /Volumes/My Passport/ApplescriptTest/ ‘kMDItemFSName == "sub2" && ( kMDItemContentType == "public.folder" || kMDItemFSSize == 0 )’ "
→ error “Failed to create query for ‘Passport/ApplescriptTest/ kMDItemFSName == "sub2" && ( kMDItemContentType == "public.folder" || kMDItemFSSize == 0 )’.” number 1
end tell

Peter

Hello.

I have added the missing “quoted form of” in the example above. I recreated your folder structure, and tested it, it worked fine. I am sorry for the trouble, the spaces in filenames was something that slipped by me, when I wrote the example.

Hi McUsr

It appears that the problem with external drives is again a space. the name of the first one I tried it on “My Passport” when I went to one with out spaces it worked again.

You can see the difference “onlyin” the name of the volume “My Passport” but the failed query shows only “Passport”

do shell script "mdfind -onlyin /Volumes/My Passport/ApplescriptTest/ ‘kMDItemFSName == "sub2" && ( kMDItemContentType == "public.folder" || kMDItemFSSize == 0 )’ "
→ error “Failed to create query for 'Passport/ApplescriptTest/ kMDItemFSName == "sub2" && ( kMDItemContentType == "public.folder" || kMDItemFSSize == 0 )'.” number 1

Thanks

Peter

If you spell out folder names directly like that, then you need to put single quotes around them like this:

'/My passort drive/with lots a/ spaces/in its/directory names/'

when you are using such a path name in a variable, then you should apply qouted form.

Either “set myvar to quoted form of posix path of (the filename)”

Alternatively

set myvar to quoted form of myvar” (if the posix path is already acquired.)

I hope this helps. :slight_smile:

Hi McUsr

Had not see your last post have made that correction and it worked on the example thanks so much. It is amazingly quick.

I have three questions if you would not mind.

  1. The search term appears to be case sensitive can I change that even if it is an option for the user.
  2. I notice that the handler returns all the folders that start with the search term although tit is set to accept the first paragraph. Can I put a repeat loop in the handler so I can select the place I want?
  3. Can I make the search term specific again even as a user option?

I have a long way to go to get my eamils to use this ruotine but cannot thank you enough for your assistance.

Peter:)

Question 1
Nope, I think mdfind by itself is case sensitive, so that is a no no. if your search term consist of 5 letters, then we’d have 120 possible permutations. If you need case insensitivity dearly, then we’d have to generate a list by finder.

Question 2.

Haha, :slight_smile: I just posted a handler for those things: MacScripter / Easy to use yet versatile handler for finding folders by mdfind see if you can use that one! :slight_smile:

But you can use the handler in the post, with an empty search string, and it will return all folders, as long as the search predicate isn’t exact.

The handler will return a full list of folders if you set the result set to “every” or “all”

Question 3.
Yes, the handler a search predicate with “exact”, which only returns exact matches.

Hi McUsr

I have tried to combine your handler wit your previous suggestions but somehow I am not passing either the “resulttype” or “searchpredicate” correctly. I have forced them both to one of the options within the handler that works. when i use display dialog to see what they are at the handler they both appear to be correct. to make sure no spelling mistakes I copied the items from the handler to the “choose list”. Obviously doing something wrong. I have tried both as strings and text and that did not help.
If I set the searhpredicate within the handler I then get a problem with resulttype. If I set both it works so I think it is the way I am passing the data?

Here is the scrip as I have it

--This was developed with the help of  McUsr to return all the folders with a name of the search term. It is a start to be used as a way to file copies of incoming mail messages
set folderpath to quoted form of (POSIX path of (choose folder)) -- sets file path to folders selected 

display dialog "Enter Name of Folder(s) you are looking for" default answer "" --In a working application this will be provided either as subject or name sender recipient
set subject to text returned of result
--Added to allow for which entry is require  First,Last, All
set resultType to choose from list {"First", "Last", "All", "Every"} with prompt "Select Which Entry is required" as text
--Added to set up the degree of c=accuracy in the search term
set searchPredicate to choose from list {"contains", "begins with", "ends with", "exact"} with prompt "Determine Location of Search Name in String" as text

set objItem to my findFolderOnly(resultType, searchPredicate, subject, folderpath)
if objItem is not {} then
	
	tell application "System Events" to tell disk item objItem to set {resultType, searchPredicate, ParentFolder, Foldername} to {POSIX path of container of it, name of it}
	
	display dialog "Path to Folder:" & objItem & return & "Parent Folder of Folder " & ParentFolder & return & "Name of Folder: " & Foldername
else
	display dialog "Not found"
end if


on findFolderOnly(resultType, searchPredicate, searchterm, directoryToSearchIn)
	-- © 2012 McUsr and put into public domain, you may not post this on its own, nor make it available in a public repository.
	-- please refer to this link: http://macscripter.net/viewtopic.php?pid=156879#p156879
	--set directoryToSearchIn to quoted form of directoryToSearchIn
	display dialog "Search Predicate is " & searchPredicate & return & "Result type is " & resultType
	--set searchPredicate to "contains"
	if searchPredicate is "contains" then
		set searchterm to "\"*" & searchterm & "*\""
	else if searchPredicate is "begins with" then
		set searchterm to "\"" & searchterm & "*\""
	else if searchPredicate is "ends with" then
		set searchterm to "\"*" & searchterm & "\""
	else if searchPredicate is "exact" then
		set searchterm to "\"" & searchterm & "\""
	else
		error "The search predicate is misspelled!" number 4000
	end if
	if resultType = "first" or resultType = "last" or resultType = "all" or resultType = "every" then
		
		try
			local theResult
			set theResult to (do shell script "mdfind -onlyin " & directoryToSearchIn & " 'kMDItemFSName == " & searchterm & " && ( kMDItemContentType == \"public.folder\" || kMDItemFSSize == 0 )' ")
			if resultType = "first" then
				return first paragraph of theResult
			else if resultType = "last" then
				return last paragraph of theResult
			else if resultType = "every" or resultType = "all" then
				return theResult
			end if
		on error
			return {}
		end try
	else
		error "Wrong value for resulttype" number 4000
	end if
end findFolderOnly

thanks again

Peter :slight_smile:

Hello.

First of all, the choose from list, returns a list, so the searchPredicate, and the resultType parameters won’t get evaluated as text, and therefore fails.

Thanks for making me aware of this, I’ll enforce the handler with your findings. :slight_smile: In the mean time, use the handler like this:

set objItem to my findFolderOnly(resultType as text, searchPredicate as text, subject, folderpath)

The line that sets the parent folder, and folder name also needs to be fixed, to something like this:

tell application "System Events" to tell disk item objItem to set {ParentFolder, Foldername} to {POSIX path of container of it, name of it}

I see that you have changed the handler, it would be nice if you didn’t, or gave a notice when you did, as people may think that it is the original one, when it isn’t. (I think of the removal of “set quoted form of”, mainly, I understand the need for the display dialog for debugging purposes, (and so do others).