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.
Stefan hasnt posted any scripts in this particular thread.
If you’re also referring to the (seemingly unrelated) thread to which @Homer712 linked above, I can only see one script posted by Stefan, which uses the find command line tool to enumerate files. While his command soecifically excludes files with names that begin with a dot that would be hidden in Finder, it would enumerate other files that are hidden in Finder (i.e. by way of the hidden file flag).
Bear in mind that Finder isn’t in charge of filesystems. It’s merely a front-facing graphical tool that shows users only what’s important/relevant for the average user to know about. It obfuscates a heck of a lot actually, and I don’t think it’s even capable of showing or providing access to character devices, sockets, fifos, etc. So, in principle, the only kinds of implementations for directory enumeration that one would expect to yield results that agree with the Finder are the ones that use Finder to do the enumerating. And that’s rarely a good idea for anyone not planning on living forever.
I have totally misunderstood this thread. Thank you for the explanation. Although I’m relatively new here, that is no excuse for not reading threads more thoroughly and then taking time to understand them, and if I still don’t, asking questions.
Dont go and flagellate yourself, or anything. It’s not a big deal. I pointed it out just in case you had intended to post your message into another thread and it ended up here by mistake while leaving you none-the-wiser. But if it’s simply a case of getting the wrong end of the stick about what’s being discussed in a particular thread, then I’d be surprised if this ends up being the last time you ever do this. Im pretty sure I did it myself a couple of hours ago, so I’ll wait and see what the response is to that.
These threads can end up getting really long, and if you happen to have dyslexia on top of this, it quicky becomes as easy to interpret as reading tea leaves at the bottom of a cup.
Prior to retiring (quite a few years ago now) I was an Electrical Engineer, and in any project there were three things that were always important. Detail, detail and more detail. I love being here on MacScripter over morning coffee. When I’m reading threads that catch my interest, I just need to make sure I’m fully awake.
A little coercion ensures we know the path structure. And I love using TIDs! It’s like they’re secretly machine code! CHOMP! CHOMP!
set myPath to "/users/test/downloads/folder-1/folder-2/folder-3/folder-4/"
set myPath to ((POSIX file myPath) as alias) as text
set {prevTIDS, text item delimiters} to {text item delimiters, ":"}
set {myPath, text item delimiters} to {text items of myPath, prevTIDS}
(length of myPath) - 2
Thank you for mentioning me, but the code is from post #9 and I would have never suggested “snail-paced” entire contents of the Finder.
Back to the topic: I’m wondering that nobody has proposed an AppleScriptObjC solution yet
use AppleScript version "2.5"
use framework "Foundation"
use scripting additions
set aFolder to POSIX path of (choose folder)
set theURL to current application's NSURL's fileURLWithPath:aFolder
set depth to (theURL's pathComponents()'s |count|()) - 1
I tested Homer’s scripts on my 2023 Mac mini, and they quickly returned accurate results for folders in my home folder. I also tested the scripts on a folder on an external drive that contained 39,248 files in 8,121 folders. Once again, the scripts returned accurate results and only took a few seconds to execute. About the only issue I encountered was the scripts returned counts for the ~/Library folder when run on my home folder, and that was excessively slow. Anyways, Homer’s scripts may be a bit off-topic, and their source is an open question, but they are quite useful IMO.
use scripting additions
set x to "/Users/viking/Library/Containers/mongoose"
display dialog (do shell script "/bin/zsh -c 'print ${#${(@s:/:)0}}' " & x) as text
Result: 5
This is splitting the string x into an array and counting its elements.
To handle paths that contain white space or any characters that get treated differently by the shell, you need to use x's quoted form to produce a properly-escaped, single-quoted path.
Having used various UNIX systems long before DOS, Windows, either macOS, or Linux, I simply do not space punctuate file or folder names. So, for my path example, the code is correct.
However, you are also correct for those that do use space punctuation in the filesystem, and perhaps I should have used a multiple space path example and x’s quoted form to cover that usage case.
The as text cast has evolved as a habit over the years and I agree is superfluous.
The following checks to see if the path is to a folder and is a slight modification of Stefan’s ASObjC suggestion. The script assumes that a package is considered not to be a folder and that the path is to an item that exists.
use framework "Foundation"
use scripting additions
set thePath to "/Users/Robert/Working/Test Folder/" --> 4
set thePath to "/Users/Robert/Working/Test Folder" --> 4
set thePath to "/Users/Robert/Working/Test File.txt" --> 3
set thePath to "/Users/Robert/Working/Test App.app" --> 3
set theURL to current application's NSURL's fileURLWithPath:thePath
set theDepth to (theURL's pathComponents()'s |count|()) - 1
set {theResult, aFolder} to (theURL's getResourceValue:(reference) forKey:(current application's NSURLIsDirectoryKey) |error|:(missing value))
set {theResult, aPackage} to (theURL's getResourceValue:(reference) forKey:(current application's NSURLIsPackageKey) |error|:(missing value))
if aFolder as boolean is false or aPackage as boolean is true then set theDepth to (theDepth - 1)
return theDepth