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/”
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.
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
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
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.
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"}
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.
This following solution will check that the path is actually a directory if it does not end with a “/”.
set thePath to "/Users/test/downloads/folder-1/folder-2/folder-3/folder-4/"
if last character of thePath = "/" then
set folderDepth to ((do shell script "echo " & quoted form of ¬
thePath & " |tr -dc '/' |wc -c") as number) - 1
else
set folderDepth to ((do shell script "if [[ -d " & quoted form of thePath & " ]] ;then echo " & ¬
quoted form of thePath & " |tr -dc '/' |wc -c" & " ;fi") as number)
end if
if folderDepth > 0 then
activate
display dialog ("Chosen Folder Depth: " & folderDepth) as text ¬
buttons {"Cancel", "OK"} default button "OK" giving up after 3
else
activate
display dialog "The Chosen Path Isn't A Folder!" buttons ¬
{"Cancel", "OK"} default button "OK" giving up after 3
end if
wch1zpink. I tested your script as written, except that I deleted the forward slash in line 1 after folder-4. The script shows a dialog stating “The Chosen Path Isn’t A Folder”. Is that correct or am I missing something?
EDIT: I think I understand now. If the path ends with a forward slash, the script assumes that the path is to a folder. If the path does not end with a forward slash, the script checks to see if the folder exists and, if not, returns an error.
Since shell commands are on the table, why not use stat -F, which should indicate definitively whether a file is a directory or not. You might require more options should the files being tested include symbolic links.
When I recreated the original path in post #1, “/users/test/downloads/folder-1/folder-2/folder-3/folder-4/” and then ran every script here, almost all of them gave me the correct result, which was 7.
If I changed the path to: “/users/documents/”, the only script that would come up with the correct result, which was 66 (I counted them) was peavine’s in post #11.
I think you’ve posted this in the wrong thread, as those scripts pertain to counting the number of files or folders in a directory subtree. This thread is about determining the distance from a given directory back up to the root directory. Thus /users/documents, apart from being a very strange place for a documents folder to reside (or a very strange name to give to a user), is two levels down from the root directory, and not 66.