Count directory depth

The last time I needed this kind of code I used a text item delimiter routine to count the slashes in a posix path, but this method is rather inelegant, isn’t there a simpler way to find out how deep a path is?

Let’s say I’ve this path:
“/users/test/downloads/folder-1/folder-2/folder-3/folder-4/”

How to find out 7?

Why do you consider it inelegant. It works perfectly fine and is how I would do it

set myPath to "/users/test/downloads/folder-1/folder-2/folder-3/folder-4/"
set tid to text item delimiters -- save current delimiters
set text item delimiters to "/"
set myPath to rest of text items of myPath
set c to count myPath
if item -1 of myPath = "" then set c to c - 1
set text item delimiters to tid -- reset delimters

Well in the past I didn’t care about code methods in use, the only important thing was that code worked.

But this approach in general is a bit cumbersome because you’ve to write more code. Trying to write better code is not just more interesting, but you finish faster and your code gets slimmer.
Therefore my question.

I don’t know of any other way to get the result.

Here is another option.

set aFolder to "/users/test/downloads/folder-1/folder-2/folder-3/folder-4/"

set folderDepth to (do shell script "echo " & quoted form of ¬
	aFolder & " |tr '/' '\n' |sed '/^$/d' |wc -l") as number
1 Like

Using “do shell script” has a lot of overhead. Ran both thru Script Geek.
pure AppleScript version was 170 times faster

@Joy
You could use the class NSURL and the property pathComponents
It gives 8 because it count the first /… so we set -1 to get 7

use framework "Foundation"
use scripting additions

set thePath to "/users/test/downloads/folder-1/folder-2/folder-3/folder-4/"
set theURL to current application's |NSURL|'s fileURLWithPath:thePath
return (theURL's pathComponents()'s |count|()) - 1

I was curious and tested the three suggestions on my 2023 Mac mini. I used Script Geek set to obsessive mode with 0 iterations (the tested code is run once).

robertfern - returned 0.0000 which means the timing result was less than a half of a tenth of a millisecond

wch1zpink - 6 milliseconds

Fredrik71 - 0.3 milliseconds (with Foundation framework in memory)

Just as a matter of personal preference, I would normally use robertfern’s suggestion. If text item delimiters are not an option for some reason, a repeat loop can be used and it takes a tenth of a millisecond.

set thePath to "/users/test/downloads/folder-1/folder-2/folder-3/folder-4/"
set theCharacters to characters of thePath
set theCount to 0
repeat with aCharacter in theCharacters
	if contents of aCharacter is "/" then set theCount to theCount + 1
end repeat
if (item -1 of theCharacters) is "/" then set theCount to theCount - 1
return theCount --> 7
1 Like

Here is other approach from @peavine example.
This one is equal in the performance as my AppleScriptObjC version.

set thePath to "/users/test/downloads/folder-1/folder-2/folder-3/folder-4/"
set charList to characters of thePath
set i to 0
repeat with char in charList
	if contents of char is "/" then
		set i to i + 1
	end if
end repeat
return i - 1

Fredrik71. Your script appears to return an incorrect result in the following instance:

set thePath to "/users/test/downloads/folder-1/folder-2/folder-3/folder-4" -- returns 6 but should be 7

You forgot the last slash / in your test of my script

1 Like

I think that if the path doesn’t end with a “/”, the script must explicitly check if the last item is a folder (and not a file). Folder paths may not always end with a “/”. (If I understand the goal of this script correctly.)

Here is a complete solution which allows you to choose any folder to return it’s folder depth.

Actually, since the choose folder command will always return a path with the ending “/”, there is no need for any code to check what the last character is. There’s also no need to check whether the last item in the path is a file or not, because we have chosen a folder.

activate
set aFolder to POSIX path of (choose folder)

set folderDepth to ((do shell script "echo " & quoted form of ¬
	aFolder & " |tr -dc '/' |wc -c") as number) - 1

activate
display dialog ("Chosen Folder Depth: " & folderDepth) as text ¬
	buttons {"Cancel", "OK"} default button "OK" giving up after 3

I understand your point. However, it just doesn’t cover all possible use cases. It requires a user interaction to choose a folder. In reality, as you know, this folder path can come from all kind of sources, not necessarily the choose folder command.

If you use scripting additions POSIX path it will always end with slash /

FWIW, System Events does not include a trailing forward slash:

set theFolder to choose folder
tell application "System Events" to set theFiles to POSIX path of every folder in theFolder --> {"/Users/Robert/Desktop/New Folder 2", "/Users/Robert/Desktop/New Folder 1"}
1 Like

Sure, but while I don’t want to split hairs here, unless you verify that that last component without a trailing “/” is a folder you won’t be fully covered. As @peavine’s example with System Events demonstrates. In real-life scripts that path can come from an infinite number of sources and methods that may or may not include a trailing forward slash. I just ran into this very issue too many times to know that we can’t rely on that trailing slash to be there when expected.

@leo_r
If you use my first example with AppleScriptObjC you will not have that issue.
Or you could always use scripting additions.

In that case you do if statement and do boolean test.

well i think that’s exactly my point.