dirname

If there is a topic in code exchange about basename there should be one about dirname as well.

Dirname as it works in the shell; tried to simulate as much as much code as in the dirname command line utility. Still it is about 50 times faster as in a single do shell script command.

dirName("/") --result : /
dirName("/a") --result : /
dirName("/a/b") --result : /a
dirName("/a/b/") --result : /a
dirName("/a/b//") --result : /a
dirName("/a/b/c") --result : /a/b
dirName("/a/b/c/") --result : /a/b
dirName("/a/b//c") --result : /a/b
dirName("/a//b/c") --result : /a//b; this is correct

on dirName(__n)
	script s
		property AoB : missing value
	end script
	if __n's length < 2 then return __n
	set s's AoB to id of __n
	repeat until last item of s's AoB is not 47
		set s's AoB to items 1 thru -2 of s's AoB
	end repeat
	set {p, b} to {{}, {}}
	repeat with char in s's AoB
		set end of b to contents of char
		if contents of char = 47 then
			set p to p & b
			set b to {}
		end if
	end repeat
	if p = {47} then return string id p
	repeat until last item of p is not 47
		set p to items 1 thru -2 of p
	end repeat
	return string id p
end dirName

update: Adjusted the comments; they match the result.

The results are not exactly the same then that of the shell dirname command.
dirname removes all trailing slashes in the result, except only a slash is the result. The second difference is if you call dirname with only a file name, the result would be the current directory “.”

As an example:
dirname “/” → /
dirname “a” → .
dirname “/a/b/” → /a

I tried a quick and dirty solution for that without considering performance. Maybe splitting the text with AppleScript’s text item delimiters can speed up things.


on dirname(s)
	set i to number of characters of s
	set x to i
	-- remove trailing slashes
	repeat while x > 1
		if character x of s = "/" then
			set x to x - 1
		else
			exit repeat
		end if
	end repeat
	-- remove filename
	repeat while x > 0
		if character x of s is not "/" then
			set x to x - 1
		else
			exit repeat
		end if
	end repeat
	-- remove trailing slashes
	repeat while x > 1
		if character x of s = "/" then
			set x to x - 1
		else
			exit repeat
		end if
	end repeat
	if x is 0 then
		return "."
	else
		return text 1 thru x of s
	end if
end dirname

{dirname("/a/b/c"), dirname("."), dirname("a//b"), dirname("/")} -- /a/b, . a, /

Happy scripting,
Stefan

You haven’t tested the code did you :smiley: ? My comments aren’t exactly the same as the result, sorry for that. There are no trailing slashes in my example code either (meanwhile I adjusted the comments of my previous post). For pwd, I didn’t support it because AppleScript doesn’t have such thing so I thought it isn’t needed

Yep, you’re right, I just tested the last ones which results where like the comments…:rolleyes:

Nevertheless I think you should consider to return the current directory even if you have no use for it now. There might be cases when this comes handy - for example analysing an installer log file.

Slightly faster than DJ’s, about the same as Stefan’s (on my machine):

dirName("/") --result : /
dirName("/a") --result : /
dirName("/a/b") --result : /a
dirName("/a/b/") --result : /a
dirName("/a/b//") --result : /a
dirName("/a/b/c") --result : /a/b
dirName("/a/b/c/") --result : /a/b
dirName("/a/b//c") --result : /a/b
dirName("/a//b/c") --result : /a//b; this is correct
dirName("aardvark/") -- result : .

on dirName(__n)
	set namesFound to 0
	if ((count __n) > 0) then
		set astid to AppleScript's text item delimiters
		set AppleScript's text item delimiters to "/"
		set TIs to __n's text items
		repeat with i from (count TIs) to 1 by -1
			if ((count item i of TIs) > 0) then
				set namesFound to namesFound + 1
				if (namesFound is 2) then exit repeat
			end if
		end repeat
		set dn to text 1 thru text item i of __n
		set AppleScript's text item delimiters to astid
	end if
	
	if ((namesFound < 2) and (__n does not start with "/")) then set dn to "."
	
	return dn
end dirName

Nigel, I like that one. I assume it will be even faster if you play with real paths which usually will have longer filenames than just one character.