Are there _built_in_ "basename" and "dirname" AppleScript functions?

I’m using 10.7.4, and I’m looking for built-in AppleScript functions to extract the base name and the directory name of an arbitrary Posix path (these functions are commonly called “basename” and “dirname”). I know I can do this via do shell script by calling appropriate code written in Perl, Python, Ruby, etc., and I know there are numerous hand-coded AppleScript implementations of these functions.

However, I’m wondering whether by now (10.7.4), Apple has finally come up with any built-in AppleScript functions to perform these common tasks, so we don’t all have to keep borrowing code and re-inventing the wheel.

If not, no big deal. I’m used to the level of functionality provided within AppleScript. But I’m wondering if perhaps there is something new that might have been recently added to AppleScript to provide these functions.

To be clear, given an arbitrary Posix path such as “/a/b/c/d/file.ext”, the dirname function would return “/a/b/c/d” and the basename function would return “file.ext”.

Thank you in advance.

Install ASObjC Runner :

tell application "ASObjC Runner"
	parsed path "/a/b/c/d/file.ext"
end tell

returns: {name extension:“ext”, name stub:“file”, path components:{“/”, “a”, “b”, “c”, “d”, “file.ext”}, name:“file.ext”, containing item:“/a/b/c/d”, name stub path:“/a/b/c/d/file”}

You don’t need Perl, Python, Ruby, etc.

do shell script "dirname /a/b/c/d/file.ext"
do shell script "basename a/b/c/d/file.ext"

Hello Nigel

I’m fond of workflow using only in the box tools but, since the delivery of Shane STANLEY’s ASObjC Runner I use it extensively.
The application is ran once during my machines startup process so, when I call it, it apply instantaneously.
This way, it’s really faster than Do Shell Script calls.

set aPath to (path to desktop as text) & "specs AppleWorks.pages:"
set anAlias to aPath as alias
set aPosixPath to POSIX path of aPath

tell application "ASObjC Runner"
	set {baseName, containerPath} to {name, containing item} of (parsed path aPath)
	--> {"specs AppleWorks.pages", "/Users/yvankoenig/Desktop"}
	set {baseName, containerPath} to {name, containing item} of (parsed path anAlias)
	--> {"specs AppleWorks.pages", "/Users/yvankoenig/Desktop"}
	set {baseName, containerPath} to {name, containing item} of (parsed path aPosixPath)
	--> {"specs AppleWorks.pages", "/Users/yvankoenig/Desktop"}
end tell

As you may see, we may pass source pathnames of different classes.
This versatility give us the ability to use a simple one liner :

tell application "ASObjC Runner" to set {baseName, containerPath} to {name, containing item} of (parsed path aPath)
	--> {"specs AppleWorks.pages", "/Users/yvankoenig/Desktop"}

without any need to know the true class of the aPath variable.

In fact, it would be fine if Apple was fair enough to buy ASObjC Runner and deliver it as an in the box tool :slight_smile:

Yvan KOENIG (VALLAURIS, France) dimanche 13 mai 2012 12:37:08

Thanks to all!

To be clear (to Nigel Garvey), my issue is not with Perl, Ruby, or Python, and I know that I can use the Unix executables “dirname” and “basename” as well as these programs. I just neglected in my original message to mention these Unix executables in the list of external programs that I do not want to use. Ideally, I’ve been looking for an AppleScript-only solution without having to either run an external executable, nor to “re-invent the wheel” by hand-coding my own “dirname” and “basename” AppleScript functions or re-using someone else’s.

Up until now, I didn’t know about ASObjC Runner, and I see that this will provide the functionality that I’m looking for. It’s technically “external” to AppleScript, but it seems to integrate well with AppleScript, and it’s provides something close to the “built in” functionality that I’m seeking. So thanks again to all of you who mentioned ASObjC Runner. I will start using it shortly.

I know you wrote built-in, but why not a simple and fast 3-liner

set thePath to "/System/Library/CoreServices/"

set {TID, text item delimiters} to {text item delimiters, "/"}
tell thePath to set {dirname, basename} to {text 1 thru text item -2, last text item}
set text item delimiters to TID

Hi, Yvan.

But Stefan’s vanilla script is still about forty times as fast as your ASObjC Runner one. :wink:

I only posted the ‘basename’ and ‘dirname’ shell scripts to demonstrate that AppleScript has built-in access to the system’s built-in Unix commands. I’d never stoop to using them myself when AppleScript has the built-in ability to be programmed to do the job itself far more efficiently.

I personally find HippoMan’s rejection of the shell scripts and of AppleScript itself for this purpose on the pretext of their being respectively “external to AppleScript” and “reinventing the wheel” totally perplexing ” especially when the solution he intends to adopt is a third-party application! AppleScript is of course a “scripting language”. “Scripting” as in orchestrating external forces like applications or bits of the system to do what’s required. “Language” as in having a syntax which enables one to write one’s own code instead of just relying on a series of push-button functions ” although you can do that too through its external contacts.

. or a 2-liner which can also handle trailing slashes: :slight_smile:

set thePath to POSIX path of (path to application "Finder")

set {TID, text item delimiters, i} to {text item delimiters, "/", ((thePath ends with "/") as integer) + 1}
set {dirname, basename, text item delimiters} to {text 1 thru text item -(i + 1) of thePath, text item -i of thePath, TID}

I would go stefan’s solution. No offence aginst Shane’s utility because it’s great. Still I would choose built-in utilities like dirname and basename above ObjCRunner. Dirname and basename are just string functions in the shell which normally must be manually coded when using shell scripts. It doesn’t resolve path names and is pure text based. That’s the reason I would go for Stefan’s method.

Yvan is right about the time before the shell script really is executed and add the time when it is done and send back into the variable is a lot of time compared to the fast dirname and basename commands. The command itself is by far the fastest way so if you’re using it in a do shell script later, embed it in the shell command. Yes, you can gain performance by writing proper shell commands. In situations like these I would go for the shell but in general you could go for Stefan’s.

My two-penneth worth…

If speed were of the essence, I’d probably use something like Nigel’s version. And I certainly wouldn’t launch ASObjC Runner just for this. Moreover, invoking the shell seems like overkill. But IMO you can’t ignore issues of readability and simplicity, especially for new or occasional users.

If you’re comfortable with shell scripting and used to using commands like dirname, then there’s a lot to be said for sticking with what you know. And if you’re familiar with text item delimiters, they would seem the obvious choice. However, the fact that (a) cramming TIDs into a couple of lines doesn’t do much for readability, and (b) the fact that it’s so easy to overlook things (as in Stefan not allowing for trailing slashes) means there’s something to be said for using a tool that says it will give you what you want directly and simply, rather than always building your own.

Treasonous talk around here, I know… :wink: