Scan File/Folder List down X-levels of hierarchy

I have a script that needs to gather file/folder lists at a certain level in a file heirarchy.

So given a simple directly like this…

–Transfer Files
----Category1
------Folder1
------File2
------Folder3
----Category2
------Folder4
------File5
------Folder6
----Category3
------Folder7
------File8
------Folder9

…I’d like to make queries like this:

“All the items 2-levels down (inside category folders)”
–>Folder1,File2,Folder3,Folder4,File5,Folder6,Folder7,File8,Folder9

“All the items 1-level down (category folder)”
–>Category1,Category2,Category3

I’d want file references that I can then do things like get the file name, file/folder size, etc. I’d like it to be a handler so I can easily tailor it to scan various heirarchy/category levels. For example, right now I only want to scan 1 and 2 levels deep, but I may eventually want to go three levels deep. So something like “my listGetter(startFolder,1)” to get a list at the first level of startFolder.

As always, THANKS!

maybe u can use (adapt) this one:

set startFolder to "macintosh hd:Users:TMA:Desktop:test"

set theList to my listGetter(startFolder, 1)

on listGetter(startFolder, theDepth)
	set retList to {}
	set tmpPosixDir to POSIX path of startFolder as string
	set tmpRetValue to do shell script "find " & quoted form of tmpPosixDir & " -type d -maxdepth " & theDepth
	if tmpRetValue ≠ "" then
		set my text item delimiters to return
		set tmpRetValue to every text item of tmpRetValue
		set my text item delimiters to ""
		repeat with tmpstring in tmpRetValue
			try
				set tmpPath to POSIX file tmpstring as string
				if tmpPath is not in retList then
					set end of retList to tmpPath
				end if
			end try
		end repeat
	end if
	return retList
end listGetter

Greets from TMA

Hi Calvin,
if you run into any problems adapting TMA’s script then maybe give this a try:

set source_folder to choose folder

tell application "Finder" to set item_list to every item of source_folder

folder_search(item_list)

on folder_search(item_list)
	repeat with this_item in item_list
		set info_record to {item_name:name, file_type:file type, file_size:size} of (info for this_item as alias)
		if folder of (info for this_item as alias) then
			display dialog "folder: " & item_name of info_record & " is" & return & "File Size: " & file_size of info_record
			tell application "Finder" to set new_folder_list to every item of this_item
			folder_search(new_folder_list)
		else
			display dialog "File: " & item_name of info_record & " is" & return & "File type: " & file_type of info_record & return & "File size: " & file_size of info_record
		end if
	end repeat
end folder_search

The script makes a list of every item in the source_folder and gets the required info for this_item, if this_item is a folder first it’ll display dialog of info for the folder then it’ll look inside that folder and repeat the routine (repeating this routine every time it finds a folder). For every file that it finds it’ll display a dialog of the info for that item.
Hope this is of some use!
Nik

Or using “find”

set startFolder to ((path to desktop) as Unicode text) & "Transfer Files:"
set depth to 2

set theItems to paragraphs of do_gatherer(startFolder, depth)

to do_gatherer(startPath, depth)
	set posixPath to quoted form of POSIX path of startPath
	return do shell script "find " & posixPath & " ! -name \".DS_Store\" -maxdepth " & depth & " -mindepth " & depth
end do_gatherer

James wins the prize for the most to-the-point solution for my handler.

Of course, since I always like to learn rather than just use someone’s script blindly…can you kindly explain the syntax of the “find” line?

return do shell script "find " & posixPath & " ! -name \".DS_Store\" -maxdepth " & depth & " -mindepth " & depth

Also, I have a property list that has folders I wish to omit from such a scan. I was just going to do checks in my loops to weed them out, but I get the impression there may be a way to do it with the find command itself, since I’m guessing the “-name” and the “.DS_Store” mean “ignore this item.”

So if this is how I re-coded it…

on listGetter(folder_to_scan, scan_level)
	set posix_path to quoted form of POSIX path of folder_to_scan
	return do shell script "find " & posix_path & " ! -name \".DS_Store\" -maxdepth " & scan_level & " -mindepth " & scan_level
end listGetter

…is there a way to have it ignore more than just .DS_Store if I have a list like:

property g_transfer_file_exceptions : {"_VACATION REQUESTS", "Temporary Items", "Trash", ".DS_Store"}

???

Thanks again James!

Hi Calvin it’s doable, but you do have to put a repeat in there to build your exception code…

set g_transfer_file_exceptions to {"_VACATION REQUESTS", "Temporary Items", "Trash"}
set transfer_file_exception_code to ""
--build your exclude list here rather than in the handler so it only happens once if the handler were to be callerd multiple times
repeat with aException in g_transfer_file_exceptions
	set transfer_file_exception_code to transfer_file_exception_code & " -o -name \"" & aException & "\""
end repeat


--set your depth, scan folder, and make the call somewhere in here


on listGetter(folder_to_scan, scan_level, transfer_file_exception_code)
	return do shell script "/usr/bin/find " & (quoted form of POSIX path of folder_to_scan & " ! \\( -name \".DS_Store\"" & transfer_file_exception_code & " \\) -maxdepth " & scan_level & " -mindepth " & scan_level
end listGetter

You could also use text item delimiters:

set g_transfer_file_exceptions to {"_VACATION REQUESTS", "Temporary Items", "Trash"}

set ASTID to AppleScript's text item delimiters
set AppleScript's text item delimiters to "\" -or -name \""
set excludeCode to text 2 thru -1 of ("" & ({""} & g_transfer_file_exceptions)) & "\""
set AppleScript's text item delimiters to ASTID

excludeCode

Nice Bruce!

Posted something a second ago, and thought I had figured it out, but didn’t. BAH.

When trying to compile this…

on listGetter(folder_to_scan, scan_level, folder_exceptions)
	--exceptions formatted for shell find
	set ASTID to AppleScript's text item delimiters
	set AppleScript's text item delimiters to "\" -or -name \""
	set exclude_code to text 2 thru -1 of ("" & ({""} & folder_exceptions)) & "\""
	set AppleScript's text item delimiters to ASTID
	
	--do shell find
	set posix_path to quoted form of POSIX path of folder_to_scan
	return do shell script "/usr/bin/find " & (quoted form of POSIX path of folder_to_scan & " ! \\( -name & exclude_code & " \\) -maxdepth " & scan_level & " -mindepth " & scan_level
end listGetter

…I’m getting AppleScript syntax Error | Expected ", " but found end of line. | -2741.

Any ideas? Even the forum script formatter is getting wierd about it…odd. I don’t understand the do shell part well enough to troubleshoot it.

THANKS!

(quoted form of POSIX path of folder_to_scan

Close or remove the parentheses.

It doesn’t like escaped quotes.

Seems to be the parentheses and a missing quote. Here’s what worked:

	return do shell script "/usr/bin/find " & (quoted form of POSIX path of folder_to_scan) & " ! \\( -name " & exclude_code & " \\) -maxdepth " & scan_level & " -mindepth " & scan_level

The entire script isn’t finished enough to see if the exceptions are being skipped, but the handler is gathering folder names properly, so I’ll run with it until I find a problem.

Can someone give me some explanation of just what all the do shell stuff I just did means? I don’t know the find shell command at all. I could check the man pages or something, but y’all explain these things in-context so much better. :wink:

THANKS! You folks are great.

SECOND PROBLEM:

Using the above line, it seems to be working, except I had to add a few more exceptions for OS stuff, and it’s ignoring one of my exceptions. Here’s the exceptions property:

property g_transfer_file_exceptions : {"_VACATION REQUESTS", "Temporary Items", "Trash", ".DS_Store", "TheFindByContentFolder", "TheVolumeSettingsFolder"}

Another detail, in case it matters…the script runs from my local machine, but the folder it’s scanning is on an OS X Server.

For some reason, “_VACATION REQUESTS” is not being excluded and keeps showing up in the results of the find. All the other exclusions are working fine.

Any ideas?

Thanks again.

Hi Calvin,

Can you post the exct script your using (well the relevant parts), that way I can make sure we have no typo or anything somewhere that would be screwing up your results.

Also can you post the exact ouput of the line that shouldnt be showing up?

I’ll be going over the syntax of the find btw for you shortly :smiley:

Here’s the handler as it stands:

on listGetter(folder_to_scan, scan_level, folder_exceptions)
	--exceptions formatted for shell find
	set ASTID to AppleScript's text item delimiters
	set AppleScript's text item delimiters to "\" -or -name \""
	set exclude_code to text 2 thru -1 of ("" & ({""} & folder_exceptions)) & "\""
	set AppleScript's text item delimiters to ASTID
	
	--do shell find with exceptions
	set posix_path to quoted form of POSIX path of folder_to_scan
	return do shell script "/usr/bin/find " & (quoted form of POSIX path of folder_to_scan) & " ! \\( -name " & exclude_code & " \\) -maxdepth " & scan_level & " -mindepth " & scan_level
end listGetter

Relevant properties:

property g_transfer_files_location : "Diamond Design:Transfer Files"
property g_folder_exclusions : {"_VACATION REQUESTS", "Temporary Items", "Trash", ".DS_Store", "TheFindByContentFolder", "TheVolumeSettingsFolder"}

Execution:

set are_these_old to paragraphs of listGetter(g_transfer_files_location, 3, g_folder_exclusions)

Okay so the problem is with the find command. You’ll notice that in my examples I was leaving the “.DS_Store” hard coded in. The reason for this is because the way we are building our exception string. If we remove it like you had our find command looks something like this

… -name -o -name “_VACATION REQUESTS” -o -name …

So while that does not throw up an error it is negating the first exclue item, though I’m not positive why. And just removing the intial -name doesnt work either because then the find command is starting with a or modifer and that does throw an error.

So one solution would be to simply remove “.DS_Store” from your exclude list and have it hard coded in. So you have something like this


property g_folder_exclusions : {"_VACATION REQUESTS", "Temporary Items", "Trash", "TheFindByContentFolder", "TheVolumeSettingsFolder"}

on listGetter(folder_to_scan, scan_level, folder_exceptions)
	--exceptions formatted for shell find
	set ASTID to AppleScript's text item delimiters
	set AppleScript's text item delimiters to "\" -or -name \""
	set exclude_code to text 2 thru -1 of ("" & ({""} & folder_exceptions)) & "\""
	set AppleScript's text item delimiters to ASTID
	
	--do shell find with exceptions
	return do shell script "/usr/bin/find " & (quoted form of POSIX path of folder_to_scan) & " ! \\( -name \".DS_Store\"" & exclude_code & " \\) -maxdepth " & scan_level & " -mindepth " & scan_level
end listGetter

OR

You can keep it in your exlude list, but strip our the inital -name -o from your exclude line and end up with this

property g_folder_exclusions : {"_VACATION REQUESTS", "Temporary Items", "Trash", ".DS_Store", "TheFindByContentFolder", "TheVolumeSettingsFolder"}

on listGetter(folder_to_scan, scan_level, folder_exceptions)
	--exceptions formatted for shell find
	set ASTID to AppleScript's text item delimiters
	set AppleScript's text item delimiters to "\" -or -name \""
	set exclude_code to text 2 thru -1 of ("" & ({""} & folder_exceptions)) & "\""
	set AppleScript's text item delimiters to ASTID

	--do shell find with exceptions
	return do shell script "/usr/bin/find " & (quoted form of POSIX path of folder_to_scan) & " ! \\( -name" & (text 11 thru -1 of exclude_code) & " \\) -maxdepth " & scan_level & " -mindepth " & scan_level
end listGetter

Decided it feels tidier to have all the exceptions in one place, so I went with Option #2, which seems to work like a charm.

As always, indebted to MacScripter!

Is there something special about the “Icon” file when doing these searches? I tried “Icon” and “.Icon” as exclusion criteria, but they keep showing up.

EDIT: trip down Obscurity Lane…I knew there had to be a trick with the name of the “Icon” file and it took me a while to find online…it’s “Icon\r”…there’s a return character stuffed onto the end. Charming, but now the shell find can find it. So for thos ewatching at home, if you’re trying to weed-out invible and superfluous OS folders and files, here’s what I’m using so far:

property g_exclusions_macosx : {"Temporary Items", "Trash", ".DS_Store", "TheFindByContentFolder", "TheVolumeSettingsFolder", "Icon\r"}

When you compile it, the \r is replaced, so you get:

property g_exclusions_macosx : {"Temporary Items", "Trash", ".DS_Store", "TheFindByContentFolder", "TheVolumeSettingsFolder", "Icon
"}

ON ANOTHER NOTE:
I looked-up the find command’s syntax…I think a few neurons commited suicide in the process of trying to make sense of it. :wink: I just do better with practical examples, which no man page alive ever does well for layman like me. :rolleyes:

Does this help any?

-- Pesudo-code items of entire contents of folder_to_scan whose depth is scan_level and name is not in {"_VACATION REQUESTS", "Temporary Items", "Trash", ".DS_Store", "TheFindByContentFolder", "TheVolumeSettingsFolder", "Icon\r"}

Kevin, Given your other thread would it be beneficial to return the items back in a list of mac-type references rather than shell?

If so give this a whirl for your handler

on listGetter(folder_to_scan, scan_level, folder_exceptions)
	--exceptions formatted for shell find
	set ASTID to AppleScript's text item delimiters
	set AppleScript's text item delimiters to "\" -or -name \""
	set exclude_code to text 2 thru -1 of ("" & ({""} & folder_exceptions)) & "\""
	set AppleScript's text item delimiters to ASTID
	
	--do shell find with exceptions
	return do shell script "/usr/bin/find " & (quoted form of POSIX path of folder_to_scan) & " ! \\( -name" & (text 11 thru -1 of exclude_code) & " \\) -maxdepth " & scan_level & " -mindepth " & scan_level & " -exec osascript -e 'return \"{}\" as POSIX file' \\;"
end listGetter

Doesn’t seem to return aliases, just text that says things like “file HardDisk:Folder:File.jpg”. Problem is, it says “file” for folders too such as “file HardDisk:Folder”

Is there a way to make use of that somehow?

I am finding this educational, if a bit confusing, thanks for your patience.